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

Как вы обычно решаете, какие фильмы смотреть или в какие рестораны пойти с друзьями или семьей?

Я считаю, что вы можете спросить чьи-то предложения, а иногда искать в Интернете, чтобы сделать правильный выбор. Позвольте мне объяснить два случая использования.

[Случай 1] Мы буквально ищем рейтинги ресторанов, прежде чем пробовать новый ресторан, например, как выглядят обзоры. Верно? Вот почему рейтинги очень важны, если мы хотим дать рекомендации пользователям.

Хорошо! Что делать, если мы не находим достаточно оценок для того, что ищем?

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

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

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

Метод совместной фильтрации использует матрицу пользователей и их элементы предпочтений (матрица элементов-пользователей). Затем мы сопоставляем пользователей с соответствующими интересами, вычисляем сходство их профилей и даем рекомендации. Рекомендуется тот, у кого больше всего схожих интересов. (Аналогично случаю 1)

Метод, основанный на содержании, анализирует профили пользователей на основе содержимого, извлекая особенности содержимого. Мы находим контент, похожий на тот, который уже понравился пользователю. Рекомендуется максимально похожее содержимое. (Аналогично случаю 2)

Надеюсь, вы понимаете общую идею рекомендации.

Хорошо! Я собираюсь объяснить, как мы можем создать систему рекомендаций, используя методы совместной фильтрации и на основе содержания. Мы собираемся сделать систему рекомендаций по фильмам для детей 90-х, как я упоминал ранее. Мы также можем воспользоваться этим советом и порекомендовать подрастающему поколению фильмы, которые нравились детям 90-х годов.

Давайте погрузимся в…

Мы собираемся использовать набор данных MovieLens, который содержит следующие данные:

идентификатор пользователя, идентификатор фильма, название фильма, рейтинг, теги, релевантность, отметка времени и т. д.

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

Среднее значение рейтинга.

Средний рейтинг каждого фильма.

Жанры, получившие наибольший рейтинг в наборе данных.

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

Рекомендация на основе содержания

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

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

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

vectorizer = TfidfVectorizer(analyzer='word',ngram_range=(1, 2),min_df=1)
x = vectorizer.fit_transform(df_movies_with_tags['genres'] + df_movies_with_tags['tag'])

Мы можем проверить оценки каждого тега.

#checkout TF-IDF scores of tags
df = pd.DataFrame(x[0].T.todense(), index=vectorizer.get_feature_names(), columns=["TF-IDF"])
df = df.sort_values('TF-IDF', ascending=False)

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

tag_genre_model = sigmoid_kernel(x, x)

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

Найдите похожие фильмы по movieId.

#find similar movies by movieId
def get_similar_movies(movieId, n):
  scores = []
  scores = list(enumerate(tag_genre_model[movieId_dict[movieId]]))
  scores.sort(key=lambda x: x[1], reverse=True)
return list(map(lambda x: (id_movieId_dict[x[0]], x[1]),
    scores[1: n + 1]))

Найдите название фильма по movieId.

#find movie title by movieId
def get_movie_titles(movieIds):
  movie_titles = []
  for movieId in movieIds:
    if movieId in movie_dict:
      movie_titles.append(movie_dict[movieId])
return movie_titles

Мы выбрали Человек-паук (2002) в качестве примера фильма, чтобы найти похожие фильмы. Вот что у нас получилось.

Найдите фильмы, которые смотрел userId.

def get_movies(userid):
  movie_titles = []
  movie_ids = set(df_ratings[df_ratings['userId'] == userid]
    .sort_values('rating', ascending = False)['movieId'].tolist())
return movie_ids

Наконец, мы можем создать рекомендательную функцию для конкретного пользователя. Функция принимает в качестве входных данных userId и количество рекомендаций, которые мы хотим дать, и возвращает рекомендованные нами названия фильмов.

def recommendation(userid, m=10):
similar_movies = []
  watched_movie_ids = get_movies(userid)
for movie in watched_movie_ids:
    movies = get_similar_movies(movie, 5)
    similar_movies.extend(movies)
similar_movies = sorted(similar_movies,
    key = lambda x : x[1], reverse = True)
similar_movie_ids, similarity_scores = list(zip(*similar_movies))
similar_movie_ids = [movie for movie in similar_movie_ids
    if movie not in watched_movie_ids]
similar_movie_ids = set(similar_movie_ids)
return get_movie_titles(list(similar_movie_ids)[:m])

Давайте порекомендуем userId - 755, который смотрел следующие фильмы:

История игрушек (1995), Джуманджи (1995), Ворчливые старики (1995), За долиной кукол (1970), Hiroshima Mon Amour (1959), Жара (1995) ',' Сабрина (1995) ',' Отец невесты, часть II (1995) ',' GoldenEye (1995) ',' Американский президент, The (1995) ',' Дракула: Мертвый и любящий это (1995) ', 'Никсон (1995)'

Ниже приведены 10 лучших фильмов, рекомендуемых для userId - 755:

  1. Бэтмен: Начало (2005)
  2. Левиафан (1989)
  3. Нет страны для стариков (2007) »
  4. Список Шиндлера (1993)
  5. Казино (1995)
  6. Остров головорезов (1995)
  7. Следуя (1998)
  8. Город потерянных детей, The (Cité des enfants perdus, La) (1995)
  9. Капитан Филлипс (2013) »,« Впервые, The (2012) »

ОК, круто! Это конец системы рекомендаций, основанной на содержании. Вы устали читать сейчас? Если вы просто хотите узнать о содержательной, оставшуюся тему можно пропустить.

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

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

def create_user_movie_ratings_matrix(df):
user_movie_ratings_matrix =
    df.groupby(by = ['userId','movieId'])   ['rating']
      .max().unstack().fillna(0)
return user_movie_ratings_matrix.astype(float)

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

Мы собираемся сосредоточиться на соседстве. В этом методе существуют методы на основе сходства и на основе расстояния для получения похожих пользователей или элементов.

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

#calculate the similarity score between two users
def find_similarity(userId1, userId2, 
  user_movie_ratings_matrix=user_movie_ratings_matrix):
similarity = np.dot(user_movie_ratings_matrix.loc[userId1, :],
    user_movie_ratings_matrix.loc[userId2, :])
return similarity
#find similar users
def get_similar_users(userId,
  user_movie_ratings_matrix=user_movie_ratings_matrix, m=10):
users = []
for i in user_movie_ratings_matrix.index:
    if i != userId:
      similarity = find_similarity(userId, i)
      users.append((i, similarity))
users.sort(key=lambda x: x[1], reverse=True)
return users[:m]

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

def get_recommendations(userId, df_ratings=df_ratings_sample, m=10):
watched_movie_ids = get_movies(userId)
similar_users = get_similar_users(userId)
movies = []
for (uId, _) in similar_users:
    movies.extend(list(get_movies(uId)))
    movies = list(set(movies))
    movies = [movie for movie in movies if movie
      not in watched_movie_ids]
return get_movie_titles(movies[:m])

Мы выбираем тот же userId - 138446, чтобы сравнить результаты с первым подходом. (На основе содержания). Ниже приведены рекомендованные фильмы, которые у нас есть.

  1. В ожидании выдоха (1995)
  2. Том и Гек (1995)
  3. Внезапная смерть (1995)
  4. Денежный поезд (1995)
  5. Убийцы (1995)
  6. Сейчас и тогда (1995)
  7. За морем времени (1995)
  8. Требуется два (1995)
  9. Плачь, любимая страна (1995)
  10. Ангел-хранитель (1994)

Что вы думаете о результатах? Как вы думаете, какая рекомендация более точна?

Оценки рекомендательной системы

Еще один важный рекомендательный факт. Оценка производительности по рекомендации не может быть решена только на основе значений ошибок, таких как среднеквадратическая ошибка (MSE) или средняя абсолютная ошибка (MAE).

Нам лучше провести онлайн-тестирование или AB-тестирование, которое представляет собой экспериментальное исследование двух вариантов. Например, создание двух групп пользователей, таких как A и B. Затем порекомендуйте фильмы Группе A с использованием контента и Группе B с совместной работой. Наконец, сравните удовлетворенность пользователей.

Эти подходы, которые мы сделали, наверняка нуждались в оптимизации.

Дальнейшее улучшение

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

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

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

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

Спасибо, что дочитали до этого места!

Вы можете получить код здесь: https://github.com/AI-Leap/90s_kids_movie_recommender