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.