Построение и тестирование рекомендательных систем с неожиданностью, шаг за шагом

Узнайте, как создать свой собственный механизм рекомендаций с помощью Python и Surprise Library, Collaborative Filtering

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

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

Мы будем работать с Book-Crossing, набором данных рейтингов книг для разработки алгоритмов системы рекомендаций, с Библиотекой сюрпризов, созданной Nicolas Hug. Давайте начнем!

Данные

Данные Book-Crossing состоят из трех таблиц, мы будем использовать две из них: таблица пользователей и таблица рейтингов книг.

user = pd.read_csv('BX-Users.csv', sep=';', error_bad_lines=False, encoding="latin-1")
user.columns = ['userID', 'Location', 'Age']
rating = pd.read_csv('BX-Book-Ratings.csv', sep=';', error_bad_lines=False, encoding="latin-1")
rating.columns = ['userID', 'ISBN', 'bookRating']
df = pd.merge(user, rating, on='userID', how='inner')
df.drop(['Location', 'Age'], axis=1, inplace=True)
df.head()

EDA

Распределение рейтингов

Мы видим, что более 62% всех оценок в данных равны 0, и очень мало оценок - 1 или 2 или 3, низкие рейтинги означают, что они, как правило, очень плохие.

Распределение рейтингов по книгам

df.groupby('ISBN')['bookRating'].count().reset_index().sort_values('bookRating', ascending=False)[:10]

Большинство книг в данных получили менее 5 оценок, и очень немногие книги имеют много оценок, хотя книга с самым высоким рейтингом получила 2502 оценки.

Распределение рейтингов по пользователям

df.groupby('userID')['bookRating'].count().reset_index().sort_values('bookRating', ascending=False)[:10]

Большинство пользователей в данных дали менее 5 оценок, и немногие пользователи дали много оценок, хотя самый продуктивный пользователь дал 13 602 оценки.

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

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

Сюрприз

Чтобы загрузить набор данных из вышеупомянутого фрейма данных pandas, мы будем использовать метод load_from_df(), нам также понадобится объект Reader и должен быть указан параметр rating_scale. Фрейм данных должен иметь три столбца, соответствующих идентификаторам пользователей, идентификаторам элементов и рейтингам в этом порядке. Таким образом, каждая строка соответствует данному рейтингу.

reader = Reader(rating_scale=(0, 9))
data = Dataset.load_from_df(df_new[['userID', 'ISBN', 'bookRating']], reader)

С помощью библиотеки Surprise мы протестируем следующие алгоритмы:

Базовые алгоритмы

NormalPredictor

  • Алгоритм NormalPredictor предсказывает случайную оценку на основе распределения обучающего набора, которое предполагается нормальным. Это один из самых простых алгоритмов, который мало работает.

BaselineOnly

  • BaselineOnly алгоритм предсказывает базовую оценку для данного пользователя и элемента.

k-NN алгоритмы

KNNBasic

  • KNNBasic - это базовый алгоритм совместной фильтрации.

KNNWithMeans

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

KNNWithZScore

  • KNNWithZScore - это базовый алгоритм совместной фильтрации, учитывающий нормализацию z-оценки каждого пользователя.

KNNBaseline

  • KNNBaseline - это базовый алгоритм совместной фильтрации, учитывающий базовый рейтинг.

Алгоритмы на основе матричной факторизации

СВД

SVDpp

  • Алгоритм SVDpp является расширением SVD, учитывающим неявные рейтинги.

NMF

  • NMF - это алгоритм совместной фильтрации, основанный на неотрицательной матричной факторизации. Очень похоже на СВД.

Склон один

Совместная кластеризация

Мы используем «rmse» в качестве метрики точности прогнозов.

Тренируйся и предсказывай

Алгоритм BaselineOnly дал нам наилучшее среднеквадратичное отклонение, поэтому мы будем обучать и прогнозировать с BaselineOnly и использовать метод альтернативных наименьших квадратов (ALS).

print('Using ALS')
bsl_options = {'method': 'als',
               'n_epochs': 5,
               'reg_u': 12,
               'reg_i': 5
               }
algo = BaselineOnly(bsl_options=bsl_options)
cross_validate(algo, data, measures=['RMSE'], cv=3, verbose=False)

Мы используем train_test_split() для выборки набора поездов и набора тестов с заданными размерами и используем метрику точности rmse. Затем мы воспользуемся методом fit(), который обучит алгоритм на обучающем наборе, и методом test(), который вернет прогнозы, сделанные на основе набора тестов.

trainset, testset = train_test_split(data, test_size=0.25)
algo = BaselineOnly(bsl_options=bsl_options)
predictions = algo.fit(trainset).test(testset)
accuracy.rmse(predictions)

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

Лучшие прогнозы:

Вышеизложенное - лучшие прогнозы, и они не являются удачными предположениями. Поскольку Ui находится где-то между 25 и 146, они не очень маленькие, а это означает, что значительное количество пользователей оценили целевую книгу.

Худшие прогнозы:

Худшие прогнозы выглядят довольно неожиданно. Давайте подробнее рассмотрим последний ISBN «055358264X». Книгу оценили 47 пользователей, пользователь «26544» получил оценку 10, наш алгоритм BaselineOnly предсказывает, что этот пользователь получит оценку 0.

import matplotlib.pyplot as plt
%matplotlib notebook
df_new.loc[df_new['ISBN'] == '055358264X']['bookRating'].hist()
plt.xlabel('rating')
plt.ylabel('Number of ratings')
plt.title('Number of ratings book ISBN 055358264X has received')
plt.show();

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

Вот и все! Надеюсь, вам понравилось рекомендательное (а точнее, рейтинговое предсказание) путешествие с Сюрпризом. Блокнот Jupyter можно найти на Github. Счастливых праздников!

Ссылка: Сюрприз документация »