Перейти к содержанию
Публикация AiManual

Как неполные данные о покупках ломают метрики рекомендательных систем: разбор кейса Coveo

Разбор кейса Coveo SIGIR eCOM 2021: почему отсутствие записи о покупке не равно промаху рекомендательной системы, как считать Hit@20 на 748 сессиях из 60 000 и

Коротко

Что будет в материале

  1. 01

    Почему отсутствие записи о покупке не промах рекомендательной системы

  2. 02

    Как считать Hit@20, когда цель известна не для всех сессий

  3. 03

    Правила формирования цели: окно 24 часа и границы сессии

  4. 04

    Разделение данных на исторический, обучающий и проверочный периоды

В датасете Coveo SIGIR eCOM 2021 Public Data Release 1.0.0 неполнота регистрации событий означает, что пустая строка с покупкой не доказывает, что покупки не было. Поэтому сессии без записанной покупки не записываются в промахи. Из 60 000 подготовленных сессий метрику Hit@20 посчитали по 748, где после запроса есть зарегистрированная покупка, и модель дала 441 попадание: 58,96%. Остальные 59 252 сессии получили статус «цель неизвестна», а не «промах».

Арифметика простая. Если бы все 59 252 сессии посчитали промахами, метрика упала бы до 441 / 60 000 = 0,735%, то есть примерно 0,7%. Одно и то же поведение модели превращается либо в 58,96%, либо в 0,7% в зависимости от того, что попало в знаменатель. Разрыв почти в 84 раза больше похож на ошибку измерения, чем на характеристику качества ранжирования.

Почему отсутствие записи о покупке не промах рекомендательной системы

Что именно предупреждают авторы Coveo

Проблема заложена в самом источнике данных. Авторы набора Coveo SIGIR eCOM 2021 предупреждают, что регистрация событий в браузере может быть неполной. Порядок строк в файле тоже не гарантирует порядок действий: последовательность приходится восстанавливать по идентификатору сессии и отметке времени события.

Это меняет правила чтения файлов. Нельзя считать, что строки идут по времени, и нельзя считать, что список событий полон. В Public Data Release 1.0.0 три CSV: действия посетителей, поисковые запросы и признаки товаров. Идентификаторы товаров обезличены, дальше они называются SKU.

Как неполнота данных превращается в ложные промахи

Механика искажения простая. Модель рекомендует товар, посетитель его покупает, но событие purchase не попадает в выгрузку. Система оценки видит запрос без покупки и выставляет промах. Ошибка не в модели, а в трактовке пустого места.

Ключевая тонкость: даже если одна покупка в сессии записана, сведения о других могут отсутствовать. Поэтому статус «покупки не было» нельзя присвоить ни одной сессии без записи purchase. Чтение всех опубликованных строк сессии, действий и поиска, доказывает лишь то, что в коде подготовки ничего не потеряно. Полноту самой выгрузки покупок это не подтверждает, и подтверждения такой полноты для Coveo не нашлось.

Вывод для методики: знаменатель метрики попаданий включает только сессии с известной целью. Все остальные сессии дают 59 252 неизвестных исхода, а не 59 252 промаха.

Как считать Hit@20, когда цель известна не для всех сессий

Hit@20 проверяет, попал ли хотя бы один товар из цели в первые 20 рекомендаций. На 748 сессиях с зарегистрированной покупкой после запроса модель дала 441 попадание, это 58,96%.

Вариант расчётаЧислительЗнаменательРезультат
Только сессии с известной целью44174858,96%
Все подготовленные сессии44160 000около 0,7%

Почему 748, а не 60 000: логика знаменателя

Сессия без цели не может быть ни попаданием, ни промахом. У неё нет товара, с которым можно сравнить выдачу, поэтому в знаменатель она не входит. Причина в определении цели, которое использовал автор разбора: цель ограничена товарами из зарегистрированных покупок после запроса. Всё, что не подтверждено записью, целью не считается.

Аналогия: оценивать точность стрелка по выстрелам, где мишень вообще была видна. Если часть выстрелов сделана в темноте и результат неизвестен, включение их в статистику как промахов описывает не навык стрелка, а качество освещения.

При этом 59 252 сессии не выбрасываются из проекта. Они остаются в выборке, потому что в момент рекомендации система не знает, появится ли позже запись о покупке. Их используют для других проверок, а не для Hit@20.

Как интерпретировать 58,96% и чего не стоит делать

58,96% означают долю сессий с известной целью, где хотя бы один рекомендованный товар совпал с покупкой. Непопаданий на этом подмножестве 307.

Из метрики нельзя вывести утверждение «модель ошибается в 41% случаев». Часть этих 307 сессий может объясняться неполнотой данных: покупка была, но осталась незарегистрированной. Сравнивать 58,96% с метриками, посчитанными на полной выборке без учёта неполноты, тоже нельзя: знаменатели описывают разные множества.

Правила формирования цели: окно 24 часа и границы сессии

Запросом считается первый просмотр товара с корректным SKU в сессии. Цель ограничивается товарами из зарегистрированных покупок в течение 24 часов после этого запроса, в пределах сессии. Если после первого просмотра записи о покупке ещё нет, формируется одна выдача. Если покупка уже записана, запрос не допускается, а более поздние выдачи этой сессии в эксперимент не входят. Такие правила формирования цели и выдачи описаны в исходном разборе.

Сессии уже выделены: у действий одного визита общий обезличенный идентификатор, а перерыв более 30 минут начинает новую сессию. Поэтому окно внутри сессии ограничено ещё и её собственным завершением.

Почему окно именно 24 часа

Длина окна выбирается как компромисс. Короткое окно теряет отложенные покупки: посетитель вернулся к товару через день и купил. Слишком длинное окно размывает связь между запросом и покупкой, и цель начинает приписывать модели чужие заслуги. 24 часа здесь выбраны как верхняя граница, за которой связь «запрос - покупка» становится спорной. Это параметр методики, а не измеренная константа: на своих данных его стоит проверять, сравнивая метрику при разных значениях.

Что делать с событиями в одну и ту же секунду

Если несколько событий имеют одну отметку времени, они учитываются вместе: определить, какое произошло раньше, невозможно. Это влияет на выбор первого просмотра товара и на состав цели. Отбрасывать такие события нельзя, иначе из выборки уйдут целые группы действий.

Разделение данных на исторический, обучающий и проверочный периоды

Данные делятся по времени на три части: исторический период, обучающий и проверочный. Разделение по времени, а не случайное, не даёт будущим покупкам просочиться в прошлое.

Зачем нужен исторический период

На историческом периоде строится граф товаров и считаются признаки, которые не должны зависеть от будущих событий. Совместные покупки и просмотры для построения связей берутся только оттуда. Если включить в граф покупки из проверочного периода, модель получит подсказку о том, что ей предстоит предсказать, и метрика потеряет смысл.

Почему сессии без цели остаются в выборке

Исключение из знаменателя Hit@20 не означает исключения из пайплайна. Система в момент рекомендации не знает, появится ли позже запись о покупке, и должна отвечать на запросы всех сессий. Поэтому сессии без цели проходят через все периоды, а участие в обучающих сравнениях и расчёте Hit@20 ограничивается теми, у кого цель есть.

Отбор кандидатов и промахи: что должно оставаться в метрике

Пайплайн двухступенчатый. Граф товаров и другие источники находят кандидатов. LightGBM ранжирует их и выбирает до 20 товаров, которые уходят в выдачу.

Как граф товаров и LightGBM делят ответственность

Граф отвечает за полноту: если нужный товар не попал в список кандидатов, ранжировщик его не увидит. LightGBM отвечает за порядок: из готового пула он поднимает наверх то, что вероятнее окажется в цели. Промах графа ранжировщик компенсировать не может.

Почему нельзя выкидывать сессии с промахами отбора

Соблазн понятный: убрать сессии, где кандидат не нашёлся, и метрика сразу подрастёт. Такая оценка перестаёт описывать систему, которая работает в продакшене. Hit@20 должен отражать полный пайплайн, включая отбор кандидатов. Если товар из цели не попал в пул кандидатов, это промах системы, и он попадает в знаменатель как непопадание.

Проверка времени расчёта и отказов на сессиях без цели

59 252 сессии без зарегистрированной покупки прогоняются через локальный HTTP API уже обученной модели. Для метрики попаданий они бесполезны, для эксплуатации нет.

Какие метрики снимать на сессиях без цели

  • время ответа API на один запрос, включая построение кандидатов и ранжирование;
  • долю отказов и исключений при обработке сессии;
  • долю пустых выдач, когда модель не вернула ни одного товара;
  • поведение на сессиях, где после запроса вообще нет событий.

Эти метрики не заменяют Hit@20, а дополняют её. Система с попаданием 58,96% и падением на каждом десятом запросе не годится для продакшена, и сессии без цели показывают это раньше, чем жалобы пользователей.

Как воспроизвести пайплайн: код и инструкция

Описанные правила собраны в проекте с графом товаров, LightGBM и локальным HTTP API. Код и инструкция воспроизведения лежат в репозитории RecSys-Coveo.

Порядок работы:

  1. скачать Coveo SIGIR eCOM 2021 Public Data Release 1.0.0: три CSV с действиями, поисковыми запросами и признаками товаров;
  2. разметить сессии по идентификатору визита и перерыву в 30 минут, восстановить порядок событий по времени;
  3. определить запрос как первый просмотр товара с корректным SKU и собрать цель из зарегистрированных покупок в течение 24 часов;
  4. разделить данные на исторический, обучающий и проверочный периоды;
  5. построить граф товаров на историческом периоде и обучить LightGBM на обучающем;
  6. поднять локальный HTTP API, прогнать проверочный период и посчитать Hit@20 по сессиям с известной целью;
  7. отдельно замерить время отклика и отказы на сессиях без цели.

Начинать стоит с проверки знаменателя. Если в отчёте Hit@20 делится на число всех сессий, метрика почти наверняка занижена, и первый шаг - посчитать, у какой доли сессий цель известна.

Подписаться на канал