ВВЕДЕНИЕ
Я люблю фильмы. На большинство фильмов, которые я смотрю, влияют их рейтинги и обзоры в Интернете. Я решил создать простую рекомендательную систему для фильмов, развернутых на Streamlit, на основе оценок других пользователей, собранных в наборе данных Movie Lens из Университета Миннесоты. Позвольте мне показать вам, как это сделать, но перед этим немного об алгоритме KNN.
K-БЛИЖАЙШИЙ СОСЕД
K-ближайший сосед — это алгоритм непараметрического обучения, используемый как для задач классификации, так и для задач регрессии. Проще говоря, KNN ничего не знает о своих данных. Стратегия обучения алгоритма K-ближайших соседей состоит в том, чтобы найти наблюдения, наиболее похожие на то, которое вы должны предсказать, предполагая, что похожие вещи находятся рядом друг с другом.
Давайте рассмотрим это в контексте аналогии;
Как только поступает новый пример или ввод x из ранее невиданных данных, алгоритм KNN находит самые близкие k-обучающие примеры к x и возвращает наиболее часто встречающийся класс среди них в случае классификации или средний класс в случае регрессии.
КАК Я СОЗДАЛ СИСТЕМУ РЕКОМЕНДАЦИЙ
ПРЕДВАРИТЕЛЬНАЯ ОБРАБОТКА
Предварительная обработка была самой важной частью процесса сборки. Было крайне важно изменить данные, чтобы классификатор мог давать хорошие классификации.
- ЗАГРУЗКА И ПРОСМОТР ДАННЫХ
Первым шагом в предварительной обработке является загрузка данных и быстрое исследование данных, чтобы понять, как их следует предварительно обрабатывать. Это верно для любого проекта машинного обучения или науки о данных.
- Импортируйте соответствующие модули
import pandas as pd import numpy as np import seaborn as sns from scipy.sparse import csr_matrix import matplotlib.pyplot as plt from tqdm import tqdm
2. Загрузите данные
movies = pd.read_csv("movies.csv") ratings = pd.read_csv('ratings.csv')
3. Быстрое понимание данных
movies.head() # You can do same for the ratings data to quickly have an understanding of how the data is structured.
ratings.head()
Из быстрого исследования данных мы можем заметить, что фильмы и рейтинги имеют общую функцию movieId. Таким образом, мы можем создать окончательный набор данных на основе рейтингов и получить доступ к деталям любого фильма из идентификатора позже.
final_dataset = ratings.pivot(index='movieId', columns='userId', values='rating') final_dataset
2. КОНВЕРТАЦИЯ В НУЛЕВОЙ РЕЙТИНГ
Из рис. 3 видно, что в наборах данных много пропущенных значений. Эти отсутствующие значения представляют все фильмы без рейтинга. Модели плохо работают с отсутствующими значениями, поэтому важно заменить их в любом наборе данных перед дальнейшей обработкой. Все фильмы без рейтинга были заменены нулями.
final_dataset.fillna(0, inplace=True) final_dataset.head()
Следующие шаги должны обеспечить доверие к рейтингам фильмов и доверие к людям, которые оценивали фильмы. Мы хотим убрать фальшивые рейтинги и «ботов».
#votes for each movie num_user_voted = ratings.groupby('movieId')['rating'].agg('count') #votes by each user num_movies_voted = ratings.groupby('userId')['rating'].agg('count')
3. УДАЛЕНИЕ ПОЛЬЗОВАТЕЛЕЙ, КОТОРЫЕ НЕ ДОСТАТОЧНЫ ОЦЕНОК
Пользователи, которые не оценили до 50 фильмов, были удалены из набора данных. Логика заключается в том, что если вы не оценили до 50 фильмов, ваши оценки, вероятно, будут искажать данные, или вы просто не можете быть законным оценщиком фильмов. Я учитывал только тех, кто оценил больше фильмов, чем 50.
# A user should have rated at least 50 movies movie_idx = final_dataset.iloc[val[0]]['movieId'] f,ax = plt.subplots(1,1,figsize=(16,4)) plt.scatter(num_user_voted.index, num_user_voted, color='mediumseagreen') plt.axhline(y=10, color='r') plt.xlabel('MovieId') plt.ylabel('Number of users Voted') plt.show() final_dataset = final_dataset.loc[num_user_voted[num_user_voted > 10].index, :]
4. УДАЛЕНИЕ ФИЛЬМОВ БЕЗ ОЦЕНОК
Фильмы с рейтингом менее 10 были удалены. Если в фильме меньше 10 фильмов, это означает, что многие люди его не смотрели. Эта система рекомендует популярные фильмы, которые могут вам понравиться.
# A movie should have at least 10 user ratings f,ax = plt.subplots(1,1, figsize=(16,4)) plt.scatter(num_movies_voted.index, num_movies_voted, color='mediumseagreen') plt.axhline(y=50, color='r') plt.xlabel('UserId') plt.ylabel('No of votes by user') plt.show() final_dataset = final_dataset.loc[:,num_movies_voted[num_movies_voted>50].index]
Теперь давайте снова взглянем на набор данных.
final_dataset
У нас осталось всего 2121 фильм из более чем 190 000. Однако с нашим набором данных что-то не так. Хотите угадать? Да!, это редко. Избавимся от разреженности.
5. УДАЛЕНИЕ РАЗРЯДНЫХ ДАННЫХ
Набор данных скудный. Обратите внимание, что большинство фильмов имеют нулевой рейтинг, и поэтому их необходимо удалить.
csr_data = csr_matrix(final_dataset.values)
Предварительная обработка завершена! Урааааа! Вы на полпути к построению модели.
ПОСТРОЕНИЕ МОДЕЛИ KNN
- МОДЕЛЬ
В качестве гиперпараметров использовался алгоритм KNN с 20 K-соседями и евклидовым расстоянием. Я выбрал 20 наугад. Однако есть несколько способов не делать это случайным образом. Проверьте ссылки на статьи о том, как выбрать оптимальное количество соседей.
from sklearn.neighbors import NearestNeighbors model = NearestNeighbors(metric='cosine',algorithm='brute', n_neighbors=20, n_jobs=-1) model.fit(csr_data)
2. ПОЛУЧЕНИЕ РЕКОМЕНДАЦИЙ ФИЛЬМА
Используйте эту функцию, чтобы получить список из 5 фильмов, похожих на фильм, который вы запрашиваете.
def get_movie_recommendation(movie_name): movie_name = movie_name.lower() n_movies_to_recommend = 5 movies['title1'] = movies['title'].str.lower() movie_list = movies[movies['title1'].str.contains(movie_name)] if len(movie_list): movie_idx = movie_list.iloc[0]['movieId'] movie_idx = final_dataset[final_dataset['movieId']== movie_idx].index[0] distances, indices = model.kneighbors(csr_data[movie_idx], n_neighbors=n_movies_to_recommend+1) rec_movie_indices = sorted(list(zip(indices.squeeze().tolist(), distances.squeeze().tolist())),key=lambda x:x[1])[:0:-1] recommend_frame = [] for val in rec_movie_indices: movie_idx = final_dataset.iloc[val[0]]['movieId'] idx = movies[movies['movieId']== movie_idx].index recommend_frame.append({'Title':movies.iloc[idx]['title'].values[0],'Genre':movies.iloc[idx]['genres'].values[0]}) df = pd.DataFrame(recommend_frame,index=range(1,n_movies_to_recommend+1)) return df else: return 'No movies found. Please Check for another movie' get_movie_recommendation("Iron man")
Я думаю, что наша модель хорошо справляется с предсказаниями. Что вы думаете?
3. Бонус
Я пошел еще дальше, чтобы дать пользователям возможность проверить n лучших фильмов с самым высоким рейтингом. «n» задается пользователем. Как это сделать смотрите ниже
def get_most_watched(n): most_watched = [] most_watched_movies = num_user_voted.sort_values().tail(n).index.to_list() for val in most_watched_movies: idx_1 = movies[movies['movieId']== val].index name = movies.iloc[idx_1]['title'].values[0] most_watched.append({'Title':name}) df_most_watched = pd.DataFrame(most_watched,index=range(1,n+1)) return df_most_watched get_most_watched(10)
Поздравляю🎉🎉. Вы успешно создали сайт рекомендаций фильмов с помощью KNN, если до этого момента успешно следовали руководству. Теперь другая захватывающая часть — развертывание алгоритма на Streamlit. Ознакомьтесь с этим руководством в следующем посте этой серии.
По этой ссылке можно получить доступ к коду в моей учетной записи Github.
Попробуйте мое приложение, развернутое на Streamlit здесь.
Напишите мне в Твиттере с вашими вопросами, предложениями и т. д.
ССЫЛКИ
Нахождение значения K: https://towardsdatascience.com/how-to-find-the-optimal-value-of-k-in-knn-35d936e554eb
Github: https://github.com/Awontiirim/asiak-movengine
Приложение Streamlit: https://share.streamlit.io/awontiirim/asiak-movengine/main_page.py
Твиттер: https://twitter.com/NathanielAsiak