Как ИИ рекомендует вам фильмы — загляните под капот, используя TF-IDF и косинусное сходство.

В этом сообщении блога мы рассмотрим использование двух мощных методов обработки естественного языка, TF-IDF и косинусного подобия, для создания системы рекомендаций фильмов с использованием набора данных IMDB. Сначала мы обсудим концепцию TF-IDF, которая расшифровывается как Term Frequency-Inverse Document Frequency, и то, как она используется для представления текстовых данных в числовом формате. Далее мы углубимся в понятие косинусного подобия, меры сходства между двумя ненулевыми векторами, и как его можно использовать для сравнения сходства двух фрагментов текста. Наконец, мы применим эти методы на практике, создав систему рекомендаций фильмов, которая предлагает фильмы, похожие на заданный входной фильм, на основе их сюжетных описаний.

В первой части эксперимента мы будем использовать набор данных от Kaggle, ссылку можно взять здесь:



На этом наборе данных мы протестируем алгоритм TF-IDF и косинусное сходство, и, если он сработает, мы соберем больше данных с сайта IMDb и протестируем нашу систему рекомендаций.

Во-первых, давайте импортируем модули, которые мы будем использовать:

import numpy as np
import pandas as pd
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.metrics.pairwise import cosine_similarity

Давайте получим и изучим файл CSV из Kaggle:

data = pd.read_csv('/content/IMDB WITH BERT/imdb_top_1000.csv')
data.head()

Результат упакован в DataFrame и должен выглядеть после очистки данных, заключающейся в уменьшении ненужных нам столбцов:

from sklearn.feature_extraction.text import TfidfVectorizer
 
tfidf = TfidfVectorizer(stop_words='english')

data['Overview'] = data['Overview'].fillna('')

tfidf_matrix = tfidf.fit_transform(data['Overview'])

tfidf_matrix.shape

Этот код импортирует класс TfidfVectorizer из модуля sklearn.feature_extraction.text.

Затем он создает экземпляр класса с именем tfidf и устанавливает для параметра stop_words значение «english», что указывает векторизатору игнорировать общеупотребительные английские слова, которые содержат мало значимой информации (например, «the», «and», «is»).

Затем он заменяет все отсутствующие значения в столбце «Обзор» фрейма данных «данные» пустой строкой.

Затем он вызывает метод fit_transform для объекта tfidf, передавая в качестве входных данных столбец «Обзор» фрейма данных «данные». Это создает разреженное матричное представление входного текста, где каждая строка представляет документ (в данном случае обзор серии), а каждый столбец представляет слово. Каждый элемент в матрице представляет значение tf-idf этого слова в этом документе.

Затем выводится атрибут формы результирующей матрицы, который возвращает кортеж количества строк и столбцов в матрице.

Таким образом, этот код использует векторизатор Tf-idf для создания разреженного матричного представления текста в столбце «Обзор» фрейма данных «данные», где каждая строка представляет документ, а каждый столбец представляет слово. Tf-idf — это показатель важности слова в документе, который обычно используется для извлечения функций из текста для использования в задачах обработки естественного языка и машинного обучения.

Далее мы будем использовать Sckit-Learn для выполнения косинусного сходства:

from sklearn.metrics.pairwise import linear_kernel

cosine_sim = linear_kernel(tfidf_matrix, tfidf_matrix)

Этот код импортирует функцию linear_kernel из модуля sklearn.metrics.pairwise.

Затем он использует эту функцию для вычисления косинусного сходства между всеми строками матрицы с именем tfidf_matrix и присваивает результат переменной с именем cosine_sim.

linear_kernel — это функция, которая вычисляет скалярное произведение двух матриц. В этом случае он вычисляет скалярное произведение tfidf_matrix с самим собой. Поскольку скалярное произведение матрицы на себя эквивалентно скалярному произведению каждой строки на каждую другую строку, это вычисление эффективно вычисляет сходство между каждой парой строк в tfidf_matrix.

Результатом является квадратная матрица с тем же количеством строк и столбцов, что и во входной матрице, где элемент в позиции (i, j) представляет сходство между i-й и j-й строками во входной матрице.

В этом случае, поскольку tfidf_matrix передается дважды, результатом является квадратная матрица с тем же количеством строк и столбцов, что и во входной матрице, где элемент в позиции (i, j) представляет косинусное сходство между i-м и j-я строка во входной матрице.

Косинусное подобие — это мера сходства между двумя ненулевыми векторами пространства внутреннего произведения, которая измеряет косинус угла между ними. Косинус 0° равен 1, а для любого другого угла он меньше 1. Таким образом, косинусное сходство, равное 1, означает, что векторы имеют одинаковое направление (или угол), а сходство, равное 0, означает, что векторы ортогональны (угол 90°).

Удалим дубликаты из названия серии:

indices = pd.Series(data.index, index=data['Series_Title']).drop_duplicates()

А теперь давайте объясним рекомендательную функцию:

def recommendations(series_title, cosine_sim=cosine_sim):
    
    idx = indices[series_title]
    sim_scores = list(enumerate(cosine_sim[idx]))
    sim_scores = sorted(sim_scores, key=lambda x: x[1], reverse=True)
    sim_scores = sim_scores[1:11]

    movie_indices = [i[0] for i in sim_scores]

    
    return data['Series_Title'].iloc[movie_indices]

Это функция под названием рекомендации, которая принимает два аргумента:

series_title: это строка, представляющая название серии, для которой функция будет генерировать рекомендации. cosine_sim: матрица сходства косинуса, которая используется для измерения сходства между различными сериями. Функция начинается с поиска индекса входного ряда в словаре индексов. Затем он создает список кортежей, где каждый кортеж содержит индекс ряда и его показатель сходства с входным рядом. Список кортежей отсортирован в порядке убывания на основе оценок сходства. Затем мы нарезали этот список, чтобы оставить только 10 наиболее похожих серий (исключая саму входную серию).

Затем функция создает список индексов первых 10 наиболее похожих рядов, извлекая первый элемент каждого кортежа из нарезанного списка.

Наконец, функция возвращает столбец «Series_Title» фрейма данных для указанных выше индексов.

Итак, в целом эта функция возвращает список заголовков серий, которые наиболее похожи на входные заголовки серий на основе показателя косинусного сходства.

Теперь давайте построим скребок. Я нашел отличный способ, как это можно сделать в этой статье:



Вот функция, которая упаковывает наши удаленные данные во фрейм данных:

# Call the download function with the array of URLS called imageArr
download_stories(imageArr)

# Attach all the data to the pandas dataframe. You can optionally write it to a CSV file as well
movieDf = pd.DataFrame({
    "Title": movie_title_arr,
    "Release_Year": movie_year_arr,
    "Genre": movie_genre_arr,
    "Synopsis": movie_synopsis_arr,
    "image_url": image_url_arr,
    "image_id": image_id_arr,
})

print('--------- Download Complete CSV Formed --------')

# movie.to_csv('file.csv', index=False) : If you want to store the file.
movieDf.head()

Момент истины! Давайте теперь поэкспериментируем, будет ли наш алгоритм работать с данными из дикой природы:

Довольно аккуратно, правда? Мы получили рекомендации для 10 новых фильмов на основе фильма, который мы выбрали!

Если вы хотите повторить эксперимент, вот блокнот Colab, чтобы вы могли попробовать это сами:



Если вам понравилась статья, подпишитесь на меня и подпишитесь, чтобы получать больше подобного контента.

Ваше здоровье!