Рубрики
Без рубрики

Создание простой рекомендательной системы на Python с использованием Панд

Автор оригинала: Usman Malik.

Вступление

Вы когда-нибудь задумывались, как Netflix предлагает вам фильмы, основанные на фильмах, которые вы уже посмотрели? Или как веб-сайты электронной коммерции отображают такие параметры, как “Часто покупаемые вместе”? Они могут выглядеть относительно простыми вариантами, но за кулисами выполняется сложный статистический алгоритм, чтобы предсказать эти рекомендации. Такие системы называются Рекомендательными системами, Рекомендательными системами или Механизмами Рекомендаций. Рекомендательная система-одно из самых известных приложений науки о данных и машинного обучения.

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

В настоящее время многие крупные технологические компании так или иначе используют Рекомендательную систему. Вы можете найти их где угодно-от Amazon (рекомендации по продуктам) до YouTube (рекомендации по видео) и Facebook (рекомендации по друзьям). Возможность рекомендовать пользователям релевантные продукты или услуги может стать огромным стимулом для компании, и именно поэтому эта техника так часто используется на многих сайтах.

В этой статье мы увидим, как мы можем построить простую рекомендательную систему на Python.

Типы рекомендательных систем

Существует два основных подхода к построению рекомендательных систем: Контентная фильтрация и Коллаборативная фильтрация:

Фильтрация На Основе Контента

При контентной фильтрации сходство между различными продуктами вычисляется на основе атрибутов продуктов. Например, в системе рекомендательных фильмов, основанных на содержании, сходство между фильмами вычисляется на основе жанров, актеров в фильме, режиссера фильма и т. Д.

Коллаборативная фильтрация

Коллаборативная фильтрация использует силу толпы. Интуиция, лежащая в основе коллаборативной фильтрации, заключается в том, что если пользователю А нравятся продукты X и Y, а другому пользователю B нравится продукт X, то есть большая вероятность, что ему понравится и продукт Y.

Возьмем, к примеру, систему рекомендаций фильмов. Предположим, огромное количество пользователей присвоили одинаковые рейтинги фильмам X и Y. Приходит новый пользователь, который присвоил такой же рейтинг фильму X,но еще не смотрел фильм Y. Коллаборативная система фильтрации порекомендует ему фильм Y.

Реализация системы рекомендаций фильмов на Python

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

Набор данных, который мы собираемся использовать для этой задачи, – это набор данных MovieLens. Чтобы загрузить набор данных, перейдите на домашнюю страницу набора данных и загрузите “ml-latest-small.zip” файл, который содержит подмножество фактического набора данных фильмов и содержит 100000 оценок для 9000 фильмов 700 пользователями.

Как только вы распакуете загруженный файл, вы увидите файлы “links.csv”, “movies.csv”, “ratings.csv” и “tags.csv”, а также документ “README”. В этой статье мы будем использовать файлы “movies.csv” и “ratings.csv”.

Для сценариев в этой статье распакованная папка “ml-latest-small” была помещена в папку “Datasets” на диске “E”.

Визуализация и предварительная обработка данных

Первый шаг в каждой задаче науки о данных-визуализация и предварительная обработка данных. Мы сделаем то же самое, поэтому давайте сначала импортируем файл “ratings.csv” и посмотрим, что он содержит. Выполните следующий сценарий:

import numpy as np
import pandas as pd

ratings_data = pd.read_csv("E:\Datasets\ml-latest-small\\ratings.csv")
ratings_data.head()

В приведенном выше скрипте мы используем метод read_csv() библиотеки Pandas для чтения файла “ratings.csv”. Далее мы вызываем метод head() из объекта dataframe, возвращаемого функцией read_csv () , которая будет отображать первые пять строк набора данных.

Выход выглядит примерно так:

2.5 1 31 1260759144 0
3.0 1 1029 1260759179 1
3.0 1 1061 1260759182 2
2.0 1 1129 1260759185 3
4.0 1 1172 1260759205 4

Из выходных данных видно, что файл “ratings.csv” содержит атрибуты userId, MovieID, ratings и timestamp. Каждая строка в наборе данных соответствует одному рейтингу. Столбец userId содержит идентификатор пользователя, покинувшего рейтинг. Столбец MovieID содержит идентификатор фильма, столбец rating-рейтинг, оставленный пользователем. Рейтинги могут иметь значения от 1 до 5. И, наконец, метка времени относится к тому времени, когда пользователь покинул рейтинг.

Есть одна проблема с этим набором данных. Он содержит идентификаторы фильмов, но не их названия. Нам понадобятся названия фильмов для фильмов, которые мы рекомендуем. Названия фильмов хранятся в файле “movies.csv”. Давайте импортируем файл и посмотрим, какие данные он содержит. Выполните следующий сценарий:

movie_names = pd.read_csv("E:\Datasets\ml-latest-small\\movies.csv")
movie_names.head()

Выход выглядит примерно так:

История игрушек (1995) Приключения|Анимация|Дети|Комедия|Фэнтези 1 0
Джуманджи (1995) Приключения|Дети|Фэнтези 2 1
Ворчливые старики (1995) Комедия|Романтика 3 2
Ожидание выдоха (1995) Комедия|Драма|Романтика 4 3
Отец невесты Часть II (1995) Комедия 5 4

Как вы можете видеть, этот набор данных содержит MovieID, название фильма и его жанр. Нам нужен набор данных, содержащий идентификатор пользователя, название фильма и его рейтинги. У нас есть эта информация в двух разных объектах dataframe: “ratings_data” и “movie_names”. Чтобы получить желаемую информацию в одном фрейме данных, мы можем объединить два объекта dataframes в столбце MovieID, поскольку он является общим для двух фреймов данных.

Мы можем сделать это с помощью функции merge() из библиотеки Pandas, как показано ниже:

movie_data = pd.merge(ratings_data, movie_names, on='movieId')

Теперь давайте рассмотрим наш новый фрейм данных:

movie_data.head()

Выход выглядит примерно так:

Опасные умы (1995) Драма 2.5 1 31 1260759144 0
Опасные умы (1995) Драма 3.0 7 31 851868750 1
Опасные умы (1995) Драма 4.0 31 31 12703541953 2
Опасные умы (1995) Драма 4.0 32 31 834828440 3
Опасные умы (1995) Драма 3.0 36 31 847057202 4

Вы можете видеть, что наш недавно созданный фрейм данных содержит идентификатор пользователя, название и рейтинг фильма по мере необходимости.

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

movie_data.groupby('title')['rating'].mean().head()

Выход выглядит примерно так:

title
"Great Performances" Cats (1998)           1.750000
$9.99 (2008)                               3.833333
'Hellboy': The Seeds of Creation (2004)    2.000000
'Neath the Arizona Skies (1934)            0.500000
'Round Midnight (1986)                     2.250000
Name: rating, dtype: float64

Вы можете видеть, что средние оценки не сортируются. Давайте отсортируем рейтинги в порядке убывания их средних оценок:

movie_data.groupby('title')['rating'].mean().sort_values(ascending=False).head()

Если вы выполните описанный выше сценарий, то результат будет выглядеть следующим образом:

title
Burn Up! (1991)                                     5.0
Absolute Giganten (1999)                            5.0
Gentlemen of Fortune (Dzhentlmeny udachi) (1972)    5.0
Erik the Viking (1989)                              5.0
Reality (2014)                                      5.0
Name: rating, dtype: float64

Фильмы теперь отсортированы в порядке возрастания их рейтингов. Однако есть одна проблема. Фильм может занять первое место в вышеприведенном списке, даже если только один пользователь дал ему пять звезд. Поэтому приведенные выше статистические данные могут вводить в заблуждение. Обычно фильм, который действительно хорош, получает более высокий рейтинг у большого числа пользователей.

Давайте теперь построим график общего количества рейтингов для фильма:

movie_data.groupby('title')['rating'].count().sort_values(ascending=False).head()

Выполнение приведенного выше скрипта возвращает следующие выходные данные:

title
Forrest Gump (1994)                          341
Pulp Fiction (1994)                          324
Shawshank Redemption, The (1994)             311
Silence of the Lambs, The (1991)             304
Star Wars: Episode IV - A New Hope (1977)    291
Name: rating, dtype: int64

Теперь вы можете посмотреть несколько действительно хороших фильмов наверху. Приведенный выше список подтверждает нашу точку зрения о том, что хорошие фильмы обычно получают более высокие рейтинги. Теперь мы знаем, что и средний рейтинг на фильм, и количество рейтингов на фильм являются важными атрибутами. Давайте создадим новый фрейм данных, содержащий оба этих атрибута.

Выполните следующий сценарий для создания фрейма данных ratings_mean_count и сначала добавьте средний рейтинг каждого фильма в этот фрейм данных:

ratings_mean_count = pd.DataFrame(movie_data.groupby('title')['rating'].mean())

Далее нам нужно добавить количество рейтингов для фильма в ratings_mean_count dataframe. Для этого выполните следующий сценарий:

ratings_mean_count['rating_counts'] = pd.DataFrame(movie_data.groupby('title')['rating'].count())

Теперь давайте взглянем на наш недавно созданный фрейм данных.

ratings_mean_count.head()

Вывод выглядит следующим образом:

“Великие спектакли” Кошки (1998) 1.750000 2
$9.99 (2008) 3.833333 3
“Хеллбой”: Семена творения (2004) 2.000000 1
“Под небом Аризоны” (1934) 0.500000 1
“Около полуночи” (1986) 2.250000 2

Вы можете увидеть название фильма, а также средний рейтинг и количество рейтингов для фильма.

Давайте построим гистограмму для количества рейтингов, представленных столбцом “rating_counts” в приведенном выше фрейме данных. Выполните следующий сценарий:

import matplotlib.pyplot as plt
import seaborn as sns
sns.set_style('dark')
%matplotlib inline

plt.figure(figsize=(8,6))
plt.rcParams['patch.force_edgecolor'] = True
ratings_mean_count['rating_counts'].hist(bins=50)

Вот вывод скрипта выше:

Гистограмма рейтингов

Из выходных данных видно, что большинство фильмов получили менее 50 рейтингов. В то время как количество фильмов, имеющих более 100 рейтингов, очень невелико.

Теперь построим гистограмму средних оценок. Вот код для этого:

plt.figure(figsize=(8,6))
plt.rcParams['patch.force_edgecolor'] = True
ratings_mean_count['rating'].hist(bins=50)

Выход выглядит примерно так:

Гистограмма средних оценок

Вы можете видеть, что целочисленные значения имеют более высокие бары, чем плавающие значения, так как большинство пользователей присваивают рейтинг как целочисленное значение, то есть 1, 2, 3, 4 или 5. Кроме того, очевидно, что данные имеют слабое нормальное распределение со средним значением около 3,5. В данных есть несколько выбросов.

Ранее мы говорили, что фильмы с большим количеством рейтингов обычно имеют высокий средний рейтинг, так как хороший фильм обычно хорошо известен, а известный фильм смотрит большое количество людей, и поэтому обычно имеет более высокий рейтинг. Давайте посмотрим, так ли обстоит дело и с фильмами в нашем наборе данных. Мы построим средние рейтинги против количества рейтингов:

plt.figure(figsize=(8,6))
plt.rcParams['patch.force_edgecolor'] = True
sns.jointplot(x='rating', y='rating_counts', data=ratings_mean_count, alpha=0.4)

Выход выглядит примерно так:

Средние рейтинги против количества рейтингов

График показывает, что в целом фильмы с более высокими средними рейтингами на самом деле имеют большее количество рейтингов по сравнению с фильмами с более низкими средними рейтингами.

Поиск Сходства Между Фильмами

Мы потратили довольно много времени на визуализацию и предварительную обработку наших данных. Сейчас самое время найти сходство между фильмами.

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

Чтобы создать матрицу названий фильмов и соответствующих пользовательских рейтингов, выполните следующий сценарий:

user_movie_rating = movie_data.pivot_table(index='userId', columns='title', values='rating')
user_movie_rating.head()
1 бабушка бабушка бабушка бабушка бабушка бабушка бабушка бабушка бабушка бабушка бабушка бабушка
2 бабушка бабушка бабушка бабушка бабушка бабушка бабушка бабушка бабушка бабушка бабушка бабушка
3 бабушка бабушка бабушка бабушка бабушка бабушка бабушка бабушка бабушка бабушка бабушка бабушка
4 бабушка бабушка бабушка бабушка бабушка бабушка бабушка бабушка бабушка бабушка бабушка бабушка
5 бабушка бабушка бабушка бабушка бабушка бабушка бабушка бабушка бабушка бабушка бабушка бабушка

Мы знаем, что каждый столбец содержит все оценки пользователей для конкретного фильма. Давайте найдем все пользовательские рейтинги фильма “Форрест Гамп (1994)” и найдем фильмы, похожие на него. Мы выбрали этот фильм, так как он имеет наибольшее количество рейтингов, и мы хотим найти корреляцию между фильмами, которые имеют большее количество рейтингов.

Чтобы найти рейтинг пользователей для “Forrest Gump (1994)”, выполните следующий скрипт:

forrest_gump_ratings = user_movie_rating['Forrest Gump (1994)']

Вышеприведенный сценарий вернет серию панд. Давайте посмотрим, как это выглядит.

forrest_gump_ratings.head()
userId
1    NaN
2    3.0
3    5.0
4    5.0
5    4.0
Name: Forrest Gump (1994), dtype: float64

Теперь давайте восстановим все фильмы, которые похожи на “Форрест Гамп (1994)”. Мы можем найти корреляцию между пользовательскими рейтингами “Форрест Гамп (1994)” и всех других фильмов, используя функцию corr with () , как показано ниже:

movies_like_forest_gump = user_movie_rating.corrwith(forrest_gump_ratings)

corr_forrest_gump = pd.DataFrame(movies_like_forest_gump, columns=['Correlation'])
corr_forrest_gump.dropna(inplace=True)
corr_forrest_gump.head()

В приведенном выше сценарии мы сначала извлекли список всех фильмов, связанных с “Форрестом Гампом (1994)”, вместе с их значением корреляции, используя функцию corrwith () . Затем мы создали фрейм данных, содержащий заголовок фильма и корреляционные столбцы. Затем мы удалили все значения NA из фрейма данных и отобразили его первые 5 строк с помощью функции head .

Выход выглядит примерно так:

$9.99 (2008) 1.000000
‘burbs, The (1989) 0.044946
(500) Летние дни (2009) 0.624458
*батарейки в комплект не входят (1987) 0.603023
..И справедливость для всех (1979) 0.173422

Давайте отсортируем фильмы в порядке убывания корреляции, чтобы увидеть высоко коррелированные фильмы наверху. Выполните следующий сценарий:

corr_forrest_gump.sort_values('Correlation', ascending=False).head(10)

Вот вывод скрипта выше:

$9.99 (2008) 1.0
Скажи, Что Это не Так (2001) 1.0
Метрополис (2001) 1.0
Не вижу Зла, Не Слышу Зла (1989) 1.0
Средние люди (2009) 1.0
Вода для слонов (2011) 1.0
Часы, The (2012) 1.0
Следующий фильм Чича и Чонга (1980) 1.0
Форрест Гамп (1994) 1.0
Воин (2011) 1.0

Из выходных данных видно, что фильмы, имеющие высокую корреляцию с “Форрестом Гампом (1994)”, не очень хорошо известны. Это показывает, что корреляция сама по себе не является хорошим показателем сходства, потому что может быть пользователь, который смотрел”Форест Гамп (1994)” и только один другой фильм и оценил их оба как 5.

Решение этой проблемы состоит в том, чтобы извлекать только те коррелированные фильмы, которые имеют по крайней мере более 50 рейтингов. Для этого добавим столбец rating_counts из фрейма данных rating_mean_count в наш фрейм данных corre_forrest_gump . Для этого выполните следующий сценарий:

corr_forrest_gump = corr_forrest_gump.join(ratings_mean_count['rating_counts'])
corr_forrest_gump.head()

Выход выглядит примерно так:

$9.99 (2008) 1.000000 3
‘burbs, The (1989) 0.044946 19
(500) Летние дни (2009) 0.624458 45
*батарейки в комплект не входят (1987) 0.603023 7
..И справедливость для всех (1979) 0.173422 13

Вы можете видеть, что фильм “$9.99”, который имеет самую высокую корреляцию, имеет всего три рейтинга. Это означает, что только три пользователя имеют одинаковые оценки “Forest Gump (1994)”, “$9.99”. Однако мы можем сделать вывод, что фильм не может быть объявлен похожим на другой фильм, основанный только на 3 рейтингах. Вот почему мы добавили колонку “rating_counts”. Давайте теперь отфильтруем фильмы, соотнесенные с “Форест Гамп (1994)”, которые имеют более 50 рейтингов. Следующий код сделает это:

corr_forrest_gump[corr_forrest_gump ['rating_counts']>50].sort_values('Correlation', ascending=False).head()

Вывод скрипта, выглядит примерно так:

Форрест Гамп (1994) 1.000000 341
Моя Большая жирная греческая свадьба (2002) 0.626240 51
Прекрасный ум, А (2001) 0.575922 114
Несколько хороших людей, А (1992) 0.555206 76
Ребенок на миллион долларов (2004) 0.545638 65

Теперь вы можете увидеть на выходе фильмы, которые сильно коррелируют с “Форрестом Гампом (1994)”. Фильмы в списке-одни из самых известных фильмов Голливуда, а поскольку “Форест Гамп (1994)” тоже очень известный фильм, есть большая вероятность, что эти фильмы коррелируют.

Вывод

В этой статье мы изучили, что такое рекомендательная система и как мы можем создать ее в Python, используя только библиотеку Pandas. Важно отметить, что созданная нами рекомендательная система очень проста. Реальные рекомендательные системы используют очень сложные алгоритмы и будут рассмотрены в следующей статье.

Если вы хотите узнать больше о рекомендательных системах, я предлагаю ознакомиться с книгами Практические рекомендательные системы и Рекомендательные системы: Учебник . Они гораздо глубже погружаются в эту тему и охватывают более сложные и точные методы, чем мы сделали в этой статье.