Content-based (TF-IDF)
Каждый фильм описывается числовым вектором из жанров и тегов; похожесть — косинус между векторами. Мнения других пользователей не нужны.
Теория простым языком
Content-based рекомендует «похожее на похожее»: если тебе зашёл фильм, найдём другие фильмы, похожие на него по описанию — по жанрам и тегам. Мнения других людей здесь вообще не нужны, смотрим только на сам фильм.
Главная мысль
Чтобы находить «похожие» фильмы, надо сначала научиться измерять похожесть. А чтобы её измерить — описать каждый фильм числами. Разберём это по шагам, вводя слова по дороге.
Важное отличие от коллаборативной фильтрации: здесь нам не нужны взаимодействия других людей с этим фильмом. Нужны только его собственные признаки. Поэтому новый фильм, который ещё никто не оценил, мы всё равно можем рекомендовать — у него уже есть жанры и теги.
▸Почему появился content-based подход
Шаг 1. Превращаем фильм в числа
Компьютер не понимает слова «комедия», ему нужны числа. Поэтому каждому фильму сопоставляют длинный список чисел — по одному на каждое возможное слово (жанр/тег). Если слово есть у фильма — число больше нуля, если нет — ноль.
Но не все слова одинаково полезны. Жанр «драма» есть у тысяч фильмов и почти ничего не говорит, а тег «киберпанк» — редкий и очень информативный. Чтобы редкие слова весили больше, используют приём:
Шаг 2. Меряем похожесть
Теперь у каждого фильма есть вектор. Похожесть двух фильмов — это насколько их векторы «смотрят в одну сторону».
Шаг 3. Рекомендации лично тебе
«Похожие на один фильм» — это полдела. Чтобы советовать персонально, строят твой портрет из того, что тебе уже понравилось (оценки от 4 и выше) — низкие оценки в профиль не идут, иначе мы бы учили модель на том, что тебе как раз не зашло.
# офлайн: один раз превращаем фильмы в векторы
для каждого фильма i:
v[i] = tf-idf(жанры и теги фильма i)
recommend(пользователь u, K):
liked = фильмы, которым u поставил оценку ≥ 4
profile = среднее из нормированных v[i] по liked
для каждого фильма i, не виденного u:
score[i] = cosine(profile, v[i])
вернуть K фильмов с наибольшим score▸Формулы: TF-IDF, косинус, профиль
Вес слова в фильме — это TF-IDF:
где — как часто слово встречается у фильма, — у скольких фильмов оно есть вообще, — всего фильмов. Редкое слово (маленький ) → большой → больший вес.
Косинусное сходство двух векторов:
Деление на длины и делает меру независимой от длины описания. При неотрицательных весах числитель ≥ 0, поэтому .
Профиль пользователя — среднее нормированных векторов понравившихся фильмов :
Сильная сторона: холодный старт айтема
Content-based с этим справляется: даже у только что вышедшего фильма есть жанры и описание, а значит — вектор. Его можно рекомендовать сразу, не дожидаясь ни одной оценки. Это его главный козырь.
Сильные стороны
- Решает холодный старт айтема: новому фильму хватает его описания.
- Объяснимость: «похоже по жанрам/тегам» — понятная причина рекомендации.
- Не зависит от других пользователей — работает даже с одним человеком.
Слабые стороны
- Замыкает в «пузыре»: советует только похожее на уже виденное, без сюрпризов.
- Качество ограничено качеством описаний: по одним жанрам легко промахнуться.
- Слабая точность персональных топ-списков (это видно по метрикам на этой странице).
⚠️ Что может пойти не так
- Качество = качество признаков: если у фильмов только жанры (как часто бывает), векторы грубые и похожесть смазана.
- «Пузырь фильтров»: метрики разнообразия (diversity) и новизны (novelty) у content-based обычно низкие — он крутит одно и то же по одному признаку.
- Профиль усредняет всё подряд: у человека с очень разными вкусами «средний» вектор оказывается в пустоте между кластерами и плохо описывает любой из них.
- Низкие оценки нельзя кидать в профиль наравне с высокими — иначе нелюбимое тянет рекомендации к себе.
🧠 Проверь себя: Почему новый фильм content-based может рекомендовать сразу, а коллаборативная фильтрация — нет?