Городская лента

Как поймать расхождение признаков между обучением и продом

· 2

Расхождение между условиями обучения и применения модели (training–serving skew) может возникать не в версии модели, а раньше — при сборке признака. В разборе на смоделированном сценарии с четырьмя заказами показано, как воспроизвести такое несовпадение и поставить проверку перед релизом.

В примере модель оценивает риск отмены заказа продавцом по признаку seller_cancellations_7d — числу отмен за семь суток до оформления. Для каждого заказа фиксируется время прогноза decision_at, а у события отмены есть два времени: когда оно произошло и когда запись стала доступна сервису признаков available_at. На момент прогноза учитывать можно только событие, которое уже произошло и было доступно системе.

В тестовом наборе у продавца S1 отмены произошли в 11:00 и 11:30, первая стала доступна в 11:02, вторая — только в 13:00. У S2 отмена произошла в 09:00, но запись пришла в 13:00, а заказы оценивались в 10:00, 12:00 и 14:00. Поздняя выгрузка отвечает на вопрос, сколько отмен известно сейчас, тогда как для обучающей строки нужно знать, сколько их было доступно в момент решения.

Код на стандартной библиотеке Python намеренно не обучает модель: он воспроизводит входной признак для четырёх заказов и показывает ошибку в подготовке обучающих строк. Пример выявляет две ошибки: для O1 поздняя выгрузка включает будущие отмены продавца, для O4 событие уже произошло, но сервис получил его только после прогноза. Ограничения по времени события недостаточно — нужно знать и время доступности записи.

В действующей системе тестовый набор должен содержать решения, для которых можно восстановить реальный вход модели: идентификатор запроса, идентификатор объекта, время решения, версию модели и версию вычисления признаков, значение признака на входе сервиса и источник для исторического пересчёта. Сравнение идёт в два шага: проверка контракта поля и парный пересчёт значения на момент решения с последующим сравнением с сохранённым входом. Проверка offline == online на сегодняшней базе для вчерашнего заказа не годится: оба значения уже могут содержать исправления и поздние события.

Для исторического набора нужен point-in-time join — выбор значения признака относительно времени каждой обучающей строки. Но соединение по времени события ещё не доказывает, что признак был доступен сервису тогда: при задержках или исправлениях записей нужен отдельный available_at либо сохранённая версия состояния, увиденная сервисом.

Перед релизом предлагается разделить проверки по типам сбоя: отсутствие новых обязательных полей и несовместимых типов, отсутствие необъяснённых расхождений критичных признаков на контрольных запросах, отсутствие в историческом признаке записей после decision_at, доля пропусков и устаревших значений не выше согласованного порога. После исправления признака прежнюю офлайн-метрику нельзя автоматически считать актуальной: обучение и проверку собирают заново, а в проде отдельно наблюдают входные данные и качество после появления меток.