ВВЕДЕНИЕ

Я люблю фильмы. На большинство фильмов, которые я смотрю, влияют их рейтинги и обзоры в Интернете. Я решил создать простую рекомендательную систему для фильмов, развернутых на Streamlit, на основе оценок других пользователей, собранных в наборе данных Movie Lens из Университета Миннесоты. Позвольте мне показать вам, как это сделать, но перед этим немного об алгоритме KNN.

K-БЛИЖАЙШИЙ СОСЕД

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

Давайте рассмотрим это в контексте аналогии;

Как только поступает новый пример или ввод x из ранее невиданных данных, алгоритм KNN находит самые близкие k-обучающие примеры к x и возвращает наиболее часто встречающийся класс среди них в случае классификации или средний класс в случае регрессии.

КАК Я СОЗДАЛ СИСТЕМУ РЕКОМЕНДАЦИЙ

ПРЕДВАРИТЕЛЬНАЯ ОБРАБОТКА

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

  1. ЗАГРУЗКА И ПРОСМОТР ДАННЫХ

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

  1. Импортируйте соответствующие модули
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

  1. МОДЕЛЬ

В качестве гиперпараметров использовался алгоритм 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