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

Эта форма рекомендации называется совместной фильтрацией. Совместная фильтрация — это название, данное прогнозированию или фильтрации элементов, которые могут заинтересовать пользователя, на основе предпочтений похожих пользователей. Он основан на предпосылке, что у человека А вкусы схожи с вкусами людей Б и С.

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

user_ratings_table = user_ratings.pivot(index='userId', columns='movieId', values='rating')
user_ratings_table.head()

Первое, что может стать очевидным после этого преобразования, — это количество пропущенных записей, демонстрируемое значениями NaN. Это ожидаемо — пользователь редко будет оценивать каждый элемент, и так же редко элемент будет оценен всеми людьми. Это проблема, так как большинство метрик подобия не очень хорошо обрабатывают отсутствующие данные. Как мы можем справиться с этим? Мы не можем просто удалить все строки и столбцы с отсутствующими данными, поскольку с такими разреженными данными может быть весь фрейм данных!

Точно так же вы можете предложить заполнить пустые значения нулями, что может быть допустимо для некоторых моделей машинного обучения, но может создать проблемы с механизмами рекомендаций. Если бы мы заполнили этот NaN 0, мы бы неправильно подразумевали, что им очень не нравилось! Один из вариантов — центрировать оценки каждого пользователя вокруг 0, вычитая среднее значение строки, а затем заполнять пропущенные значения 0. Это означает, что отсутствующие данные заменяются нейтральными оценками.

# Get the average rating for each user 
avg_ratings = user_ratings_table.mean(axis=1)
# Center each users ratings around 0
user_ratings_table_centered = user_ratings_table.sub(avg_ratings, axis=0)
# Fill in the missing data with 0s
user_ratings_table_normed = user_ratings_table_centered.fillna(0)

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

from sklearn.metrics.pairwise import cosine_similarity
# Generate the similarity matrix
similarities = cosine_similarity(item_ratings_table)
# Wrap the similarities in a DataFrame
cosine_similarity_df = pd.DataFrame(similarities, index=item_ratings_table.index, columns=item_ratings_table.index)
# Find the similarity values for a specific movie
cosine_similarity_series = cosine_similarity_df.loc[4]
# Sort these values highest to lowest
ordered_similarities = cosine_similarity_series.sort_values(ascending=False)
print(ordered_similarities)

Теперь вы можете находить похожие элементы на основе того, как их оценили пользователи в вашем наборе данных. Но что, если бы мы захотели не только найти элементы с одинаковыми оценками, но и предсказать, как пользователь может оценить элемент, даже если он не похож ни на один элемент, который они видели! Один из подходов состоит в том, чтобы найти похожих пользователей, используя модель K ближайших соседей, и посмотреть, понравился ли им элемент.

K-ближайшие соседи

K-NN находит k пользователей, наиболее близких по заданной метрике к рассматриваемому пользователю. Затем он усредняет оценку, которую пользователи дали элементу, для которого мы пытаемся получить оценку. В этом примере k равно 3, поэтому он находит 3 ближайших пользователя и получает их рейтинг. Это позволяет нам предсказать, как, по нашему мнению, пользователь может относиться к элементу, даже если он не видел его раньше.

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

similarities = cosine_similarity(user_ratings_table_normed)
cosine_similarity_df = pd.DataFrame(similarities, index=user_ratings_table_normed.index, columns=user_ratings_table_normed.index)
cosine_similarity_df.head()

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

# Isolate the similarity scores for user_1 and sort
user_similarity_series = cosine_similarity_df.loc[1]
ordered_similarities = user_similarity_series.sort_values(ascending=False)
# Find the top 10 most similar users
nearest_neighbors = ordered_similarities[1:11].index
# Extract the ratings of the neighbors
neighbor_ratings = user_ratings_table.reindex(nearest_neighbors)
# Calculate the mean rating given by the users nearest neighbors
print(neighbor_ratings[2].mean())

Теперь, когда вы понимаете все тонкости работы K-ближайших соседей, вы можете использовать реализацию KNN в scikit-learn, понимая, что она делает под капотом.

# Drop the column you are trying to predict
user_ratings_table_normed.drop(2, axis=1, inplace=True)
# Get the data for the user you are predicting for
target_user_x = user_ratings_table_normed.loc[[1]]
# Get the target data from user_ratings_table
other_users_y = user_ratings_table[2]
# Get the data for only those that have seen the movie
other_users_x = user_ratings_table_normed[other_users_y.notnull()]
# Remove those that have not seen the movie from the target
other_users_y.dropna(inplace=True)

Вы будете использовать other_users_x и other_users_y, чтобы подобрать KNeighborsRegressor из scikit-learn, и использовать их, чтобы предсказать, какую оценку Пользователь 1 мог бы дать фильму 2.

from sklearn.neighbors import KNeighborsRegressor
# Instantiate the user KNN model
user_knn = KNeighborsRegressor(metric='cosine', n_neighbors=10)
# Fit the model and predict the target user
user_knn.fit(other_users_x, other_users_y)
user_user_pred = user_knn.predict(target_user_x)
print(user_user_pred)

На основе элементов или на основе пользователей

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

Зачем использовать фильтрацию на основе элементов?

  • Во-первых, рекомендации, основанные на элементах, более постоянны во времени. Предпочтения пользователей меняются, например, вы можете наслаждаться анимационными фильмами, когда вы моложе, но изменить свои предпочтения на боевики в более позднем возрасте. С другой стороны, предметы обычно не меняются, фильм, который был фильмом ужасов, когда он вышел, все еще остается фильмом ужасов спустя годы.
  • Рекомендации на основе элементов могут быть проще для объяснения Сообщить пользователю, что ему порекомендовали книгу, потому что ему понравилась похожая книга (сотрудничество на основе элементов), может иметь больше смысла, чем убеждать их, что им может понравиться книга, потому что она понравилась пользователю, которого они никогда не встречали. it (сотрудничество на основе пользователей).
  • Рекомендации на основе элементов могут иметь больше предварительных расчетов. Любой интернет-магазин обычно имеет конечный известный инвентарь. Его владелец может рассчитать, какие предметы в инвентаре похожи друг на друга, а какие нет в оффлайне и использовать на своем сайте. С другой стороны, новые пользователи появляются каждый день, поэтому такой предварительный расчет не может быть полезен.

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

Зачем использовать фильтрацию на основе пользователей?

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