Метрики рекомендаций простым языком

Как понять, хороша ли рекомендательная система. Метрики ниже считаются в этом приложении для каждой модели — открой любой модуль и сравни. Строгие формулы спрятаны под «Строгая формула», чтобы простой текст оставался читаемым.

Сначала — три понятия

Top-K. Система показывает не всё, а короткий список из K лучших (например, 10). Все метрики смотрят именно на этот список.

Релевантный айтем. Тот единственный факт, который протокол про пользователя знает: спрятанный фильм, которому он поставил следующую по времени оценку.MovieLens хранит время выставления оценки, а не просмотра, так что «следующий просмотр» отсюда не следует. У нас «релевантно» = пользователь поставил оценку не ниже порога (по умолчанию ≥ 4 из 5). Чтобы проверить модель честно, мы прячем последнее взаимодействие каждого пользователя (leave-last-out) и смотрим, угадает ли его модель. Важная оговорка: неоценённые фильмы протокол не объявляет нерелевантными — он про них просто ничего не знает. Смещение от этого у двух метрик разное. Precision — нижняя оценка: истинное множество релевантного шире наблюдаемого, попаданий может стать только больше. У recall направления нет вовсе: знаменатель тоже неизвестен, и наблюдаемое значение бывает как ниже истинного, так и выше (угадали единственный известный айтем — recall 1.0, хотя на полном множестве он был бы куда меньше). Поэтому числа годятся для сравнения моделей на одном протоколе, а не как оценка «сколько процентов выдачи полезно». Подробно — на странице «Как устроен эксперимент».

Почему значения такие маленькие. Мы прячем 1 айтем и ищем его среди ~9700. Угадать его в топ-10 трудно, поэтому precision/recall в сотых долях — это нормально. Важны не абсолютные числа, а сравнение моделей между собой.

▸Какую боль решает каждая метрика

Обычная accuracy / rating RMSE не отвечает на главный вопрос — хорош ли топ-10. Каждая ранговая метрика ловит свою боль:

  • Precision@K — сколько мусора в выдаче.
  • Recall@K / HitRate@K — нашли ли нужный айтем вообще.
  • MRR — насколько высоко стоит первый правильный.
  • NDCG — насколько хорошо упорядочены релевантные айтемы с учётом позиции (и, в общем случае, силы релевантности).
  • Coverage / Novelty / Diversity — не схлопнулась ли система в популярную голову.

Поэтому смотрят набор метрик под конкретный продуктовый вопрос, а не одно число.

Метрики точности

Отвечают на вопрос «угадали ли мы то, что человеку нужно, и насколько высоко в списке».

Precision@K

0…1, выше — лучше

Какая доля из K показанных рекомендаций оказалась релевантной.

💡 «Из 10 предложенных сколько совпали с фильмом, который человек оценил следующим — и оценил высоко?»

(попаданий в топ-K) / K

▸Пример, строгая формула и подвох

Пример: Показали 10, угадали 2 → precision@10 = 2/10 = 0.2.

P@K=1K∑i=1Kreli\text{P@}K = \frac{1}{K}\sum_{i=1}^{K} \mathrm{rel}_i

reli=1\mathrm{rel}_i = 1, если айтем на позиции ii релевантен, иначе 0. Делим на KK — поэтому при одном спрятанном айтеме максимум 1/K1/K.

⚠️ Не учитывает порядок и сколько релевантного вы пропустили. При одном спрятанном айтеме максимум = 1/K, поэтому значения крошечные. И главное: девять «непопавших» айтемов — не доказанный мусор: протокол знает про пользователя ровно один положительный факт, остальное он не проверял, а не опроверг.

Recall@K

0…1, выше — лучше

Какую долю всех релевантных айтемов вы поймали в топ-K.

💡 «Из релевантных айтемов, которые известны протоколу, сколько попало в топ-K?» — известен ровно один, спрятанный.

(попаданий в топ-K) / (всего релевантных)

▸Пример, строгая формула и подвох

Пример: Релевантных всего 4, в топ-10 попали 2 → recall@10 = 2/4 = 0.5.

R@K=1∣Rel∣∑i=1Kreli\text{R@}K = \frac{1}{|\mathrm{Rel}|}\sum_{i=1}^{K} \mathrm{rel}_i

∣Rel∣|\mathrm{Rel}| — сколько всего релевантных айтемов у пользователя. У нас спрятан ровно один, поэтому ∣Rel∣=1|\mathrm{Rel}|=1 и recall совпадает с hit-rate.

⚠️ Если спрятан 1 айтем (как у нас, leave-last-out), recall = hit-rate (0 или 1 на пользователя).

Hit-rate@K

0…1, выше — лучше

Доля пользователей, у которых хотя бы одно попадание в топ-K.

💡 «У скольких людей мы угадали хоть что-то?»

(пользователей с ≥1 попаданием) / (всего пользователей)

▸Пример, строгая формула и подвох

Пример: У 41 из 1000 пользователей был хит → hit-rate = 0.041.

HR@K=1∣U∣∑u∈U1[ hitsu@K>0 ]\text{HR@}K = \frac{1}{|U|}\sum_{u \in U} \mathbf{1}\big[\,\text{hits}_u@K > 0\,\big]

Усреднение идёт по множеству оцениваемых пользователей UU. Индикатор 1[⋅]\mathbf{1}[\cdot] равен 1, если хотя бы один релевантный айтем попал в топ-K.

⚠️ Самая «прощающая» метрика: одного угаданного айтема достаточно. Не различает «угадал на 1-м месте» и «на 10-м».

MRR (Mean Reciprocal Rank)

0…1, выше — лучше

Насколько высоко в списке стоит первый релевантный айтем.

💡 «Как быстро человек дойдёт до чего-то нужного, листая сверху?»

среднее по пользователям от 1 / (позиция первого попадания)

▸Пример, строгая формула и подвох

Пример: Первый хит на 2-м месте → reciprocal rank = 1/2. Усредняем по людям.

MRR=1∣U∣∑u∈U1ranku\text{MRR} = \frac{1}{|U|}\sum_{u \in U} \frac{1}{\mathrm{rank}_u}

ranku\mathrm{rank}_u — позиция первого релевантного айтема в списке пользователя uu (если попаданий нет, слагаемое = 0).

⚠️ Смотрит только на первый хит — что дальше, неважно.

MAP@K (Mean Average Precision)

0…1, выше — лучше

Точность с учётом позиций всех релевантных айтемов в списке.

💡 «Награждаем за то, что нужное стоит выше и его много».

среднее precision на каждой позиции с попаданием, усреднённое по людям

▸Пример, строгая формула и подвох

Пример: Хиты на позициях 2 и 4 → average precision = среднее (1/2 и 2/4) = 0.5.

AP@K=1∣Rel∣∑i=1KP@i⋅reli,MAP=1∣U∣∑uAP@Ku\text{AP@}K = \frac{1}{|\mathrm{Rel}|}\sum_{i=1}^{K} \text{P@}i \cdot \mathrm{rel}_i, \quad \text{MAP} = \frac{1}{|U|}\sum_{u} \text{AP@}K_u

Для каждой позиции ii с попаданием берём precision до этой позиции, усредняем — это AP одного пользователя; MAP — среднее AP по всем. При одном спрятанном айтеме MAP совпадает с MRR.

⚠️ Самая «полная» из ранговых метрик. При одном спрятанном айтеме MAP совпадает с MRR.

NDCG@K

0…1, выше — лучше

Качество ранжирования: попадания выше ценятся сильнее, нормировано на идеал.

💡 «Угадать на 1-м месте лучше, чем на 10-м» — и это считается математически.

DCG (сумма 1/log2(позиция+1) по хитам) / идеальный DCG

▸Пример, строгая формула и подвох

Пример: Хит на позиции 1 даёт 1.0; на позиции 3 — около 0.5.

DCG@K=∑i=1Krelilog⁡2(i+1),NDCG@K=DCG@KIDCG@K\text{DCG@}K = \sum_{i=1}^{K} \frac{\mathrm{rel}_i}{\log_2(i+1)}, \quad \text{NDCG@}K = \frac{\text{DCG@}K}{\text{IDCG@}K}

IDCG@K\text{IDCG@}K — это DCG идеального порядка (все релевантные айтемы наверху). Деление на него и есть «нормировка»: 1.0 — идеальный порядок для этого пользователя и этого протокола. Сравнивать NDCG между датасетами, разными KK, наборами кандидатов или определениями релевантности нормировка не позволяет — она убирает только разницу в числе релевантных айтемов.

⚠️ Одна из ключевых offline-метрик ранжирования: учитывает и попадание, и позицию. «Нормированная» (N) — значит 1.0 это идеальный порядок.

Beyond-accuracy (за пределами точности)

Точность — не всё. Система может быть «точной», но скучной: всем советовать одни хиты. Эти метрики ловят такие перекосы.

Coverage@K

0…1, выше — обычно лучше

Какую долю всего каталога система вообще когда-либо рекомендует.

💡 «Крутим мы весь каталог или одни и те же хиты всем?»

(уникальных рекомендованных айтемов) / (всего айтемов)

▸Пример, строгая формула и подвох

Пример: Если из 9724 фильмов каталога в рекомендациях встретилось 1200 → coverage ≈ 0.12.

Coverage@K=∣⋃u∈Utop-K(u)∣∣I∣\text{Coverage@}K = \frac{\big|\bigcup_{u \in U} \text{top-}K(u)\big|}{|I|}

В числителе — объединение всех рекомендованных топ-K по всем пользователям (каждый айтем считается один раз), ∣I∣|I| — размер каталога.

⚠️ Низкий coverage — симптом концентрации выдачи, а не доказанная причина: на него влияют K, размер каталога, число оцениваемых пользователей, фильтры и политика по новым айтемам. Popularity bias — одна из гипотез, её проверяют отдельно. Высокий coverage сам по себе тоже не означает качество.

Novelty@K

в битах, выше — нишевее

Насколько непопулярны (неожиданны) рекомендованные айтемы.

💡 «Советуем мегахиты, которые и так все знают, или находки?»

среднее −log2(доля пользователей, видевших айтем)

▸Пример, строгая формула и подвох

Пример: Очень популярный фильм ≈ 1–2 бита; редкий — 8–12 бит.

Novelty@K=1K∑i∈top-K−log⁡2p(i)\text{Novelty@}K = \frac{1}{K}\sum_{i \in \text{top-}K} -\log_2 p(i)

p(i)p(i) — доля пользователей, у которых было взаимодействие с айтемом ii. Величина −log⁡2p(i)-\log_2 p(i) (само-информация) растёт, когда айтем редкий, и измеряется в битах.

⚠️ Слишком высокая novelty часто = низкая точность (советуем странное). Нужен баланс.

Diversity@K (intra-list)

0…1, выше — разнообразнее

Насколько непохожи айтемы внутри одного списка (у нас — по жанрам).

💡 «В подборке 10 разных вещей или 10 почти одинаковых?»

средняя попарная непохожесть (1 − Jaccard по жанрам) в топ-K

▸Пример, строгая формула и подвох

Пример: Список из одних боевиков → низкая diversity; микс жанров → высокая.

Diversity@K=2K(K−1)∑i<j(1−sim(i,j))\text{Diversity@}K = \frac{2}{K(K-1)}\sum_{i<j}\big(1 - \mathrm{sim}(i,j)\big)

Сумма по всем парам айтемов списка; sim(i,j)\mathrm{sim}(i,j) — близость по жанрам (Jaccard: ∣Gi∩Gj∣∣Gi∪Gj∣\frac{|G_i \cap G_j|}{|G_i \cup G_j|}). Чем меньше пары похожи, тем выше diversity.

⚠️ Контентные модели часто дают низкую diversity (рекомендуют по одному признаку). Слишком высокая — теряется релевантность.

🎚 Покрути порог релевантности

Подними планку «что считается понравившимся» и смотри, как плывут метрики и кто из моделей вырывается вперёд. Это те же числа, что в каждом модуле.

Загружаем данные

Онлайн-метрики (как меряют в проде)

⚠️ Здесь они не считаются

Все метрики выше — offline: их можно посчитать на исторических данных, что мы и делаем. Метрики ниже — online: им нужен живой трафик и реальные пользователи, поэтому в этом учебном приложении их нет. Но именно по ним принимают решения в продакшене, так что знать их обязательно.

CTR (click-through rate)

клики / показы

Доля показов, по которым кликнули. Базовый сигнал «зацепило ли».

CVR (conversion rate)

конверсии / показы — либо конверсии / клики, но не вперемешку

Доля дошедших до целевого действия (покупка, просмотр до конца, подписка). Знаменатель нужно фиксировать: conversion-per-impression и conversion-per-click — разные метрики с разной единицей наблюдения, и меняются они по-разному.

Watch / dwell time

среднее время взаимодействия на сессию

Сколько времени человек реально провёл с контентом. Ловит «кликбейт»: клик был, а смотреть не стали.

Stickiness (DAU/MAU)

активных за день / активных за месяц

Насколько плотно люди пользуются продуктом внутри месяца: 0.2 значит «в среднем 6 дней из 30». Это не retention, хотя их часто путают.

Retention

вернувшихся из когорты на день N / размер когорты

Какая доля пришедшей когорты вернулась через N дней. Главный долгосрочный сигнал здоровья продукта — рекомендации влияют на него косвенно.

Session length / depth

среднее число действий / просмотренных позиций за сессию

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

GMV (оборот)

сумма стоимости заказов за период

Суммарная стоимость проданного через площадку. В маркетплейсах часто главная цель роста, но деньги компании — это не она.

Revenue (выручка)

доход площадки за период

Доход самой площадки за период: комиссия, подписка, реклама. С GMV расходится — скидочная механика поднимает оборот и роняет выручку. Нормировки (на пользователя, на сессию, на 1000 показов) — это отдельные метрики с разными знаменателями: они отвечают на другие вопросы и двигаются по-разному, смешивать их с общей выручкой нельзя.

Guardrail-метрики

следим, чтобы не упали ниже порога

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

▸Почему offline-числа врут, и как меряют по-настоящему: A/B, gap, biased feedback

Offline↔online gap. Хорошая offline-метрика не гарантирует пользу в проде. Offline мы переигрываем прошлое (где система уже на что-то влияла), а в проде рекомендации меняют поведение людей. Поэтому offline — это фильтр-ориентир, а финальное решение — за онлайном.

A/B-тест. Случайно делим пользователей на контроль (старая модель) и тест (новая) и сравниваем целевую метрику со статистикой значимости. Золотой стандарт, но дорогой и медленный.

Interleaving. Смешиваем выдачу двух моделей в одном списке и смотрим, чьи айтемы кликают чаще. На задачах ранжирования часто оказывается чувствительнее A/B при том же трафике — но это не закон: выигрыш зависит от схемы смешивания, метрики и поведения пользователей, и его проверяют на своих данных.

Delayed / biased feedback. Отклик приходит с задержкой (покупку видно через дни) и смещён: мы наблюдаем клики только по тому, что сами показали (exposure / position bias). Поэтому «нет клика» ≠ «не понравилось» — это надо корректировать (debiasing, counterfactual-оценка).

Long-term value. Можно накрутить сиюминутный CTR кликбейтом и потерять пользователя через месяц. Зрелые системы оптимизируют долгосрочную ценность (retention, LTV), а не только мгновенный клик — поэтому и нужны guardrail-метрики.

Что важно помнить

• На нашем датасете прячется 1 айтем, поэтому recall = hit-rate и MAP = MRR. На данных с несколькими релевантными айтемами они разойдутся.

• Одна метрика — разные реализации. «NDCG@10» в разных библиотеках считают по-разному (обработка ничьих, усреднение, что считать релевантным). Сравнивать вслепую числа из двух источников нельзя — только модели внутри одного протокола, как здесь.

• Высокая offline-точность ≠ польза в проде. Реальное качество проверяют A/B-тестами на живых пользователях — offline-метрики лишь ориентир.

• Хорошая система балансирует точность и beyond-accuracy: не только угадывает, но и не загоняет всех в «пузырь» из одних и тех же хитов.

Что дальше

Чем продолжить — прямых наследников у модуля нет — это следующий шаг по карте

Можно читать параллельно — тот же блок, порядок между ними не важен

До финальной сборки не хватает ещё 13 модулей по этому пути.

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

Источники