Рекомендательная система | Вводный курс ML

Рекомендательная система

Все курсы > Вводный курс > Занятие 17

Что такое рекомендательная система?

Рекомендательная система (recommender system) стремится максимально точно предсказать предпочтения потребителя и предложить наиболее подходящий товар или услугу.

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

рекомендательная система

На этом занятии мы коротко рассмотрим основные типы рекомендательных систем, а затем создадим свою рекомендательную систему для онлайн-кинотеатра. Итак, начнем.

Типы рекомендательных систем

Для простоты выделим три типа рекомендательных систем: фильтрация по популярности, на основе содержания и коллаборативная система.

типы рекомендательных систем

Наиболее простая система выдает рекомендации на основе популярности (popularity-based recommender systems). Чем выше средний рейтинг фильма, купленного товара или статьи, тем вероятнее, что система будет рекомендовать именно их.

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

Вторым типом рекомендательных систем является, так называемая, фильтрация на основе содержания (content-based filtering). В данном случае алгоритм рекомендует товары или услуги, схожие с теми, которые пользователь приобретал ранее. Например, если вы посмотрели фильм «Матрица» с Киану Ривзом, то в дальнейшем система будет рекомендовать вам научную фантастику, а также другие фильмы с участием этого актера.

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

Третий тип — коллаборативная система (collaborative filtering). Именно ей мы и будем сегодня заниматься. Она основывается на сопоставлении пользователей и товаров (или услуг, новостей и т.д.). Математически и графически в данном случае мы работаем с матрицами предпочтений (user-item matrix).

два вида коллаборативных рекомендательных систем

Существует два вида таких систем.

Коллаборативные системы, основанные на пользователях (user-based), находят близких по предпочтениям пользователей и рекомендуют одному из них то, что уже попробовал другой.

коллаборативная рекомендательная система, основанная на пользователях (user-based)
векторы пользователей в коллаборативной системе

Системы, основанные на предмете рекомендации (item-based), сравнивают непосредственно близость товаров или услуг. Причем что отличает эту систему, сходство определяется на основе предпочтений всех пользователей, которые оставили свои оценки.

векторы товаров или услуг в коллаборативной системе

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

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

Теперь давайте пошагово обсудим, что нам предстоит сделать.

На этом занятии мы будем создавать коллаборативную систему, основанную на предмете рекомендации (item-based collaborative filtering recommender system). Впервые она была разработана компанией Amazon в 1998 году.

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

На втором этапе, мы рассчитаем расстояния от каждого фильма до ближайших векторов (других фильмов).

Для этого мы будем использовать алгоритм k-ближайших соседей (k-nearest neighbors algorithm, k-NN). Графически его работа выглядит следующим образом.

алгоритм k-ближайших соседей (k-nearest neighbors algorithm, k-NN)

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

В частности, предлагаю взять уже упомянутый фильм «Матрица» и посмотреть, предложит ли такая система фильмы с Киану Ривзом или научную фантастику.

Практика

Мы воспользуемся открытым набором данных о рейтинге фильмов MovieLens Latest Datasets. В этом датасете, в частности, содержатся названия фильмов (файл movies.csv) и оценки, которые фильмам ставили зрители (файл rating.csv).

Теперь откроем ноутбук к этому занятию

Этап 1. Подготовка данных

Я предполагаю, что вы уже скачали оба файла на свой компьютер. Теперь их нужно подгрузить в ноутбук. Это можно сделать открыв вкладку «Файлы» в меню слева и выбрав значок «Загрузить в сессионное хранилище».

загрузка данных в сессионное хранилище Google Colab. Шаг 1.
загрузка данных в сессионное хранилище Google Colab. Шаг 2.

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

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

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

Информация в этим файлах записана в формате .csv или comma-separated values, это значит, что значения одной строки просто разделены запятыми.

датасет movies из MovieLens Latest Datasets
датасет ratings из MovieLens Latest Datasets

Теперь нам необходимо создать матрицу предпочтений. Для этого мы воспользуемся сводной таблицей (pivot table). В библиотеке Pandas такую таблицу можно создать, в частности, с помощью функции pivot().

матрица предпочтений с пропущенными значениями

NaN расшифровывается как Not A Number и представляет собой наиболее частый способ отображения пропущенных значений. Так как мы будем заниматься вычислениями расстояния, каждое значение таблицы должно быть числовым. С помощью функции fillna() мы заменим NaN на ноль.

Замена пропущенных значений (imputation of missing values) — это сам по себе довольно сложный и интересный процесс, ведь далеко не всегда можно заменить пропуски нулями.

матрица предпочтений, пропущенные значения заменены нулями

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

Теперь давайте посмотрим на новую размерность, то есть на те фильмы и тех пользователей, которые остались после фильтрации данных.

Про разреженные матрицы и высокую размерность

В нашем датасете по понятным причинам очень много нулей. Такая матрица называется разреженной (sparse matrix). Одновременно, если столбцов очень много (а у нас их уже довольно много), то говорят про данные с высокой размерностью (high-dimensional data). В таком формате алгоритм будет долго обсчитывать расстояния между фильмами.

Для того, чтобы преодолеть эту сложность можно преобразовать данные в формат сжатого хранения строкой (сompressed sparse row, csr).

Посмотрим на результат.

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

сравнение исходного формата с форматом сжатого хранения строкой (csr)

Остается только сбросить индекс для удобства поиска рекомендованных фильмов.

матрица предпочтений с новым индексом

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

Этап 2. Обучение модели

Как уже было сказано, для обучения модели мы будем использовать алгоритм k-ближайших соседей. Этот алгоритм решает разные задачи, в частности, с его помощью можно заниматься регрессией (класс KNeighborsRegressor) и классификацией (класс KNeighborsClassifier).

Для наших целей нам достаточно измерить расстояние между объектами. В этом нам поможет класс машинного обучения без учителя NearestNeighbors.

Теперь давайте подробнее поговорим про параметры:

  • metric = ‘cosine’: выбираем способ измерения расстояния, в нашем случае это будет косинусное сходство
  • algorithm = ‘brute’: предполагает, что мы будем искать решение методом полного перебора (brute force search), в данном случае пространство решений позволяет перебрать все варианты
  • n_neighbors = 20: по скольким соседям ведется обучение
  • n_jobs = -1: в этом случае предполагается, что вычисления будут вестись на всех свободных ядрах процессора

Итак, мы готовы рекомендовать кино для просмотра.

Этап 3. Составление рекомендаций

Введем изначальные параметры: количество рекомендаций и на основе какого фильма мы их хотим получить (мы говорили о том, что будем смотреть на рекомендации для «Матрицы»).

Теперь найдем индекс фильма в матрице предпочтений.

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

Это индекс фильма в матрице предпочтений (после того как мы сбросили индекс). Далее с помощью метода .kneighbors() найдем индексы ближайших соседей «Матрицы».

В качестве параметров мы передадим:

  • csr_data[movie_id], то есть индекс нужного нам фильма из матрицы предпочтений в формате сжатого хранения строкой
  • n_neighbors, количество соседей (или рекомендаций); обратите внимание, мы добавляем «лишнего» соседа (+1) из-за того, что алгоритм также считает расстояние до самого себя

На выходе мы получаем массив индексов фильмов (indices) и массив расстояний (distances) до них. Для удобства преобразуем эти массивы в списки, а затем попарно объединим и создадим кортежи (tuples).

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

Посмотрим на первый элемент получившегося списка:

Остается преобразовать наш список в датафрейм.

перечень рекомендованных фильмов

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


Работа над ошибками. На видео в коде есть ошибка.

При сортировке фильмов по расстоянию указан параметр reverse = True, то есть в убывающем порядке. Из-за этого на первом месте рейтинга из десяти рекомендованных фильмов оказались картины с наибольшим расстоянием от искомого фильма.

рекомендательные системы: работа над ошибками
Неверный результат

На сайте и в ноутбуке ошибка исправлена.

Подведем итог

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

Вопросы для закрепления

Какие типы рекомендательных систем вы знаете?

Посмотреть правильный ответ

В чем заключается основное отличие двух видов коллаборативных систем?

Посмотреть правильный ответ

Что такое разреженная матрица (sparse matrix)?

Посмотреть правильный ответ

На следующем занятии мы займемся работой с изображениями.


Ответы на вопросы в комментариях

Вопрос. Если одному фильму все пользователи поставили по 10 баллов, а второму фильму — по одному баллу, то правильно ли я понимаю, что между векторами этих фильмов будет нулевой угол. И если пришел новый пользователь, который поставил первому фильму 10 баллов, то система порекомендует ему второй фильм (чего с точки зрения логики быть не должно)?

Ответ. (1) На первую часть вопроса, ответ «да», угол будет нулевой, потому что векторы коллинеарны и сонаправлены, различается только их длина.

Для вектора с двумя координатами это легко увидеть на графике.

коллинеарные векторы

Примечание: про создание графиков в Matplotlib мы подробно поговорим на курсе по анализу данных.

Можно также рассчитать косинусное сходство.

Примечание: про создание функций можно посмотреть здесь.

(2) Со второй частью вопроса, я бы вначале несколько переформулировал его, потому что если у нас есть два фильма, которым все пользователи ставят рейтинги 10 и 1 соответственно, то мы сравниваем фильмы, а не пользователей (а значит это item-based, а не user-based система).

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

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

Предположим, вышел новый фильм, и все пользователи поставили ему рейтинг 10.

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

Как мы видим, система показала, что новый фильм одинаково близок как к фильму с рейтингами 1 от всех пользователей, так и к фильму с рейтингами 10. Конечно, это противоречит здравому смыслу.

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

О некоторых сложностях создания коллаборативных систем

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

Кроме того, существует проблема холодного старта (cold start), когда либо (1) в системе в самом начале ее работы недостаточно данных для генерации рекомендаций, либо (2) пришел новый пользователь, который еще не ставил оценок, и система не знает, что ему посоветовать, либо (3) вышел новый фильм, книга, товар, которые пока не имеют рейтингов, и их схожесть с другими предметами рекомендации не так просто рассчитать.

Помимо этого, появление новых пользователей и новых фильмов вынуждают производить перерасчет расстояний в системе. Это всегда затратно с точки зрения вычислительных мощностей. В этом смысле, item-based система более удобна, чем user-based система, потому что фильмы, например, добавляются в систему реже, чем пользователи.

Весь код, приведенный в ответе, можно найти в конце ноутбука⧉.


Вопрос. Скажите можно ли разделить выборку на обучающую и тестовую? И если да, может подскажете в комментарии как?

Ответ. Один из подходов — использовать leave one out cross validation в качестве метода разделения данных и RMSE или MAE в качестве метрики качества алгоритма.

В этом случае один из рейтингов изымается из набора данных и становится тестовой выборкой, остальные рейтинги соответственно остаются в обучающей. Алгоритм обучается на имеющихся данных и делает прогноз для того рейтинга, который мы изъяли. Далее рассчитывается RMSE (который сравнивает прогнозное значение с фактическим).

Процесс повторяется для остальных рейтингов и затем рассчитывается средний RMSE по всем итерациям.

Для того чтобы сократить время вычислений, за одну итерацию можно брать не один, а несколько рейтингов, то есть использовать leave n-out cross validation.