Метрики ранжирования и рекомендаций
Если в резюме есть поиск или рекомендации, вопрос «как ты меряешь качество ранжирования» придёт обязательно. Проверяют две вещи: мыслишь ли ты в терминах верхушки списка и понимаешь ли, что офлайн-метрики на исторических кликах смещены.
Типовые формулировки: «чем NDCG лучше precision@K?», «офлайн вырос, катим в прод?», «как понять, что рекомендации не скатились в попсу?».
// Слова про смещение логов, сказанные к месту, экономят десять минут доказательств компетентности: их говорят те, кто уже видел, как офлайн-прирост умирает на проде.
Почему у всех метрик хвостик @K
В ранжировании задача другая, чем в классификации: не «угадай метку», а «расставь по порядку». И пользователь смотрит не весь порядок, а первые пять-десять позиций из пятидесяти тысяч. Поэтому метрики считают только по первым K результатам и пишут это прямо в названии: Precision@10, Recall@10.
Precision@10 - сколько из десяти показанных оказались релевантными. Recall@10 - какую долю всех релевантных для юзера объектов мы уместили в десятку.
У Recall@K есть встроенная несправедливость, о которой полезно помнить: у пользователя с тремя подходящими товарами Recall@10 может быть 1.0, а у пользователя с двумя сотнями подходящих - максимум 0.05, хотя выдача у него отличная. Сравнивать Recall@K между такими юзерами бессмысленно.
// K выбирают не от балды, а по продукту: сколько позиций реально видно на первом экране. У мобильной ленты это 3-5, у поиска - 10, у почтового автосаджеста - 1.
- релевантность
- оценка «подходит ли объект запросу». Бывает бинарной (да/нет) или градуированной, например от 0 до 3 - её ставят асессоры или выводят из поведения
NDCG: считаем руками
У Precision@K есть слепое пятно: ей всё равно, стоит релевантный результат первым или десятым. Пользователю не всё равно совсем. NDCG (normalized discounted cumulative gain) чинит именно это - и попутно умеет работать с градуированной релевантностью, а не с одним лишь «да/нет».
Сначала DCG - сумма полезностей, где вклад каждой позиции поделен на логарифм её номера: чем ниже позиция, тем меньше она весит. Пусть выдача из трёх результатов с оценками 3, 0 и 2. DCG = 3/log₂2 + 0/log₂3 + 2/log₂4 = 3/1 + 0 + 2/2 = 4.
Дальше нормировка. Идеальный порядок для тех же оценок - 3, 2, 0, его DCG = 3/1 + 2/1.585 + 0 = 4.26. Это IDCG (ideal discounted cumulative gain), потолок для конкретного запроса. NDCG = 4/4.26 = 0.94. Нормировка нужна, чтобы складывать запросы между собой: у одного релевантных пять, у другого один, и сырые DCG у них несопоставимы, а нормированные - вполне.
// Родственники: MRR (mean reciprocal rank) - обратный ранг первого попадания, 1.0 если нашли сразу, 0.5 если на второй позиции, 0.25 если на четвёртой; берут там, где нужен один правильный ответ побыстрее (автосаджест, вопрос-ответ). MAP (mean average precision) - для бинарной релевантности, когда важен весь список целиком, а не одна верхушка.
- дисконт позиции
- множитель, гасящий вклад дальних позиций. Логарифм выбран потому, что падение внимания похоже на логарифмическое: разница между 1-й и 2-й позицией огромна, между 19-й и 20-й - никакая
Офлайн смещён: клики породила старая система
Офлайн-метрики считаются на исторических логах. Ловушка в том, что логи породила прошлая версия ранжирования, и они несут её отпечаток.
Первое смещение - обратная связь. В логах есть клики только по тому, что показывали. Товар, который старая модель ни разу не подняла в топ, в офлайне выглядит нерелевантным - не потому, что плохой, а потому, что о нём просто нет данных. Новая модель, которая его находит, за это штрафуется. Круг замыкается: система хорошо ранжирует то, что сама же раньше и показывала.
Второе - позиционное смещение. Клик по первой позиции складывается из двух вещей: объект правда подошёл, и объект просто был первым. Люди кликают верх независимо от содержимого. Сырые клики как метки - это уже искажённые метки, и обучение на них закрепляет искажение.
// Лечится частично: рандомизировать порядок на маленькой доле трафика, чтобы получать несмещённые данные, и перевзвешивать клики на обратную вероятность показа - IPS (inverse propensity scoring). Полностью - только онлайном.
Чего не видно в NDCG
Точность попадания - не единственное свойство хороших рекомендаций. Рядом живут coverage (какая доля каталога попадает хоть в чьи-то рекомендации), разнообразие внутри выдачи и способность подсунуть неожиданное, но уместное.
Почему это не эстетство: модель, которая всем показывает топ-100 бестселлеров, получает прекрасный NDCG - бестселлеры и правда кликают чаще - и медленно убивает продукт. Юзеру нечего открывать, длинный хвост каталога не продаётся, через месяц он перестаёт заходить. Метрика при этом всё время росла.
Финальный судья - онлайн-эксперимент по продуктовым метрикам: CTR (click-through rate), конверсия, возвраты, удержание. Офлайн-прирост в них не обязан конвертироваться, и довольно часто не конвертируется.
// Рабочая рамка простая: офлайн - дешёвый фильтр кандидатов на A/B, онлайн - решение о выкатке. Перепутать порядок дорого: выкатишь по офлайну, а узнаешь через месяц по удержанию.
- coverage
- доля каталога, которую система вообще кому-нибудь показывает. Низкий coverage означает, что модель крутит один и тот же узкий набор
- guardrail
- метрика-ограничитель. Её не улучшают, за ней следят, чтобы она не просела, пока улучшают целевую
Как отвечать: «Офлайн NDCG вырос на 5 процентов - катим в прод?»
Пока нет. Офлайн считался на кликах старой системы, а там сидят два смещения - обратная связь и позиционное, поэтому прирост может не пережить встречу с реальным трафиком. Сначала смотрю, за счёт чего он вырос: если модель просто сузилась до популярного, coverage и разнообразие просядут, и это я держу как guardrail. Потом онлайн-эксперимент по продуктовым метрикам - CTR, конверсия, удержание. Офлайн для меня фильтр кандидатов на A/B, а не основание для выкатки.
Названы оба смещения, guardrail-свойства и правильный порядок решений. Так рассуждает человек, который уже обжигался на «офлайн вырос, онлайн упал».
На чём валят
- −Мерить рекомендации accuracy или AUC (area under the curve) по всему каталогу - задача про верхушку списка, метрики обязаны быть @K.
- −Сравнивать NDCG между периодами или датасетами с разной базой релевантных: нормировка спасает внутри запроса, но не между разными наборами данных.
- −Учить модель на сырых кликах и не замечать позиционного смещения - выучится любовь к первой позиции.
- −Максимизировать одну точность: разнообразие деградирует, выдача сходится в попсу, удержание падает позже и незаметно.
- −Считать Recall@K сопоставимым между юзерами с тремя и с двумя сотнями релевантных объектов.
Проверьте себя
Пять вопросов из банка по этой подтеме. Всего их 10, остальные разбираются в тренажёре.
- Пользователю важен один хороший ответ повыше. Какая метрика прямо про это?A)Полноту (recall), посчитанную по всей выдаче, без учёта позиции первого релевантногоB)Средняя релевантность всех показанных элементовC)MRR: усредняет 1/позиция первого релевантного результатаD)Общее число релевантных документов в базе
показать ответ и разбор
+C)MRR: усредняет 1/позиция первого релевантного результата// разбор: MRR = среднее по запросам от 1/(позиция первого релевантного): первый на 1-м месте даёт 1, на 2-м — 0.5, на 3-м — 0.33. Метрика фокусируется ровно на том, как быстро пользователь находит первый годный ответ, — уместна для навигационного поиска, QA, автоподсказок. Она игнорирует остальные релевантные (в отличие от MAP/NDCG), поэтому не годится, когда важна вся выдача.
- Чем precision@k отличается от recall@k в рекомендациях топ-k?A)Это одна и та же метрика: параметр k лишь ограничивает длину рассматриваемой выдачиB)Precision@k делит на общее число релевантных, а recall@k — на kC)precision@k — доля релевантных среди k; recall@k — доля от ВСЕХ релевантных пользователяD)Обе меряют порядок элементов внутри топ-k
показать ответ и разбор
+C)precision@k — доля релевантных среди k; recall@k — доля от ВСЕХ релевантных пользователя// разбор: Precision@k = (релевантные в топ-k)/k — насколько чиста выдача. Recall@k = (релевантные в топ-k)/(все релевантные пользователя) — какую долю нужного мы показали. При маленьком k recall почти всегда низок (всего не уместить), а precision может быть высок. Они в противофазе, и выбор зависит от продукта: витрина из 5 карточек — про precision, «не потерять важное» — про recall.
- Что показывает hit-rate (доля попаданий) в оценке рекомендаций?A)Доля случаев (юзеров/сессий), где хотя бы один релевантный попал в топ-kB)Точную позицию первого релевантного элемента у каждого отдельного пользователя в спискеC)Среднюю релевантность всех элементов каталогаD)Скорость генерации рекомендаций сервисом
показать ответ и разбор
+A)Доля случаев (юзеров/сессий), где хотя бы один релевантный попал в топ-k// разбор: Hit-rate@k — доля случаев, где хотя бы один релевантный (например, реально купленный) элемент оказался среди топ-k рекомендаций. Это грубая, но наглядная продуктовая метрика «попали или нет». Она не различает, релевантный был первым или последним в топ-k (для этого — NDCG/MRR) и не учитывает, сколько именно релевантных поймано (recall@k). Часто идёт в связке с coverage/diversity.
- Рекомендатель по офлайн-метрикам точности отличный, но пользователям выдача кажется однообразной. Какой класс метрик это ловит?A)Только accuracy — её и надо повышать дальше, ведь именно она отражает качество выдачиB)Beyond-accuracy: coverage, diversity, novelty/serendipity — ловят однообразиеC)Латентность и RPS сервиса рекомендацийD)Только precision@k на исторических кликах
показать ответ и разбор
+B)Beyond-accuracy: coverage, diversity, novelty/serendipity — ловят однообразие// разбор: Оптимизация одной точности часто скатывается к показу популярного и уже знакомого — офлайн-метрики растут, а опыт беднеет. Beyond-accuracy метрики измеряют другое: coverage — какую долю каталога вообще рекомендуем; diversity — насколько элементы в выдаче непохожи; novelty/serendipity — показываем ли неожиданно уместное. Их балансируют с точностью, потому что бизнес-эффект (удержание, LTV) зависит и от разнообразия.
- Почему метрики рекомендаций считают на срезе top-k, а не по всей выдаче?A)Пользователь видит только первые позиции — дальше выдача не влияет на опытB)Полную выдачу невозможно отсортировать за приемлемое времяC)Метрики по всей выдаче требуют разметки релевантности всего каталогаD)Так принято в библиотеках, и иначе метрики не считаются
показать ответ и разбор
+A)Пользователь видит только первые позиции — дальше выдача не влияет на опыт// разбор: Смысл среза — совпасть с тем, что человек реально увидит: первый экран, первые десять позиций. Ошибка на 500-й позиции опыта не меняет, а в среднем по всей выдаче она размоется вместе с полезным сигналом. Поэтому k выбирают не из удобства, а из продукта: сколько карточек влезает в экран и сколько люди реально пролистывают.
дальше
Теорию прочитали. Навык ставится повторением
В Сеньорчике эта подтема идёт в ежедневных сессиях: движок возвращает её, пока ответы не станут уверенными, и ведёт прогресс отдельно по каждой подтеме. Теория внутри тоже бесплатна, лимит только на количество вопросов в день.