Item-based коллаборативная фильтрация

Урок разбирает item-based коллаборативную фильтрацию — подход, который сделал знаменитым Amazon, — и объясняет, почему похожесть товаров стабильнее похожести пользователей.

Item-based CF рекомендует товары, похожие на те, с которыми пользователь уже взаимодействовал; похожесть товаров считается по тому, какие пользователи их выбирали.

Сдвиг точки зрения

Вместо «найди похожих на меня людей» item-based говорит «найди товары, похожие на те, что мне понравились». Два товара считаются похожими, если их выбирали примерно одни и те же пользователи. Если все, кто купил «хлеб», брали и «молоко», то «хлеб» и «молоко» похожи по поведению — и тому, кто взял хлеб, стоит предложить молоко.

Именно так работал классический рекомендатель Amazon, описанный в их статье про item-to-item collaborative filtering. Это до сих пор один из самых надёжных промышленных подходов.

Реализация

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

import math
from collections import defaultdict

data = {
    "u1": ["хлеб", "молоко", "масло"],
    "u2": ["хлеб", "молоко"],
    "u3": ["хлеб", "молоко", "сыр"],
    "u4": ["пиво", "чипсы"],
    "u5": ["пиво", "чипсы", "орехи"],
}

item_users = defaultdict(set)
for u, items in data.items():
    for it in items:
        item_users[it].add(u)

def cosine_sets(a, b):
    inter = len(a & b)
    return inter / (math.sqrt(len(a)) * math.sqrt(len(b))) if a and b else 0.0

target = "хлеб"
sims = {it: cosine_sets(item_users[target], item_users[it])
        for it in item_users if it != target}
print(f"Похожие на '{target}':")
for it in sorted(sims, key=lambda x: -sims[x]):
    print(f"  {it}: {round(sims[it], 3)}")

Вывод:

Похожие на 'хлеб':
  молоко: 1.0
  масло: 0.577
  сыр: 0.577
  пиво: 0.0
  чипсы: 0.0
  орехи: 0.0

«Молоко» брали все, кто брал «хлеб», — похожесть максимальна. «Пиво» и «чипсы» из другого кластера покупателей — похожесть ноль.

Почему item-based стабильнее

У этого подхода два больших практических плюса.

  • Товаров обычно меньше, чем пользователей, и их каталог меняется медленнее. Похожести «товар-товар» можно посчитать офлайн и долго переиспользовать.
  • Похожесть товаров устойчива во времени. Связь «хлеб ↔ молоко» не меняется от того, что у одного пользователя сменилось настроение. А вот похожесть пользователей «плывёт» с каждым новым кликом.

Поэтому рекомендация в рантайме сводится к дешёвой операции: взять товары из истории пользователя и подтянуть к каждому его заранее посчитанных «соседей».

Как работает под капотом

Прогноз интереса к товару i для пользователя u считают так: берут товары j, которые u уже оценил, и складывают их оценки с весами sim(i, j). Матрицу похожести товаров строят офлайн (часто оставляя для каждого товара лишь top-k соседей, чтобы она была компактной), а онлайн лишь складывают предпосчитанное — отсюда низкая задержка.

Частые ошибки

  • Путать «похоже» и «популярно». Очень популярный товар похож на всё подряд по сырому пересечению; нормируйте косинусом, иначе всем будете рекомендовать бестселлеры.
  • Хранить полную матрицу товар-товар. Для большого каталога держат только top-k соседей на товар.
  • Пересчитывать похожести в рантайме. Их считают офлайн; онлайн — только сложение весов.

Итоги

  • Item-based CF рекомендует товары, похожие на уже понравившиеся.
  • Похожесть товаров считается по пересечению их аудиторий.
  • Подход стабильнее и дешевле user-based: товаров меньше и связи устойчивее.
  • Похожести считают офлайн (top-k), а онлайн лишь складывают предпосчитанное — так работал Amazon.
Проверьте себя
1. Почему item-based CF обычно стабильнее и дешевле user-based?
AТоваров обычно меньше, чем пользователей, и связи между товарами меняются медленнее
BТовары не нужно хранить
CItem-based вообще не использует похожесть
DПользователи не кликают по товарам
2. Почему сырое пересечение аудиторий — плохая мера похожести товаров?
AОно слишком быстрое
BОчень популярный товар «похож» на всё подряд, поэтому нужна нормировка (косинус)
CОно требует оценок
DОно работает только для пользователей
py
Курс по теме
Пройдите курс «Python с нуля» — по шагам, с проверкой
8 уроков · ~14 ч · теория, упражнения и экзамен с бейджем
Открыть курс →