Офлайновая ранжирующая метрика ROC-AUC выросла на 3 процента, а онлайн A/B плоский — как найти, где они расходятся?
Офлайновая ранжирующая метрика выросла на холдауте, но онлайн-эксперимент запуска той же модели вернулся плоским.
Ограничения:
- обе цифры получены на одном и том же релизе модели;
- сплиттер прошёл A/A-проверку неделю назад;
- менять дизайн эксперимента нельзя, только диагностировать разрыв.
офлайн (холдаут, 2 недели) ROC-AUC 0.812 -> 0.836 (+3.0%)
онлайн A/B (14 дней, 1.2M польз) CTR 2.41% -> 2.43% (p = 0.38)
выручка/польз плоско (p = 0.71)
проверка логов сервинга занулено признаков: 4 из 37
пайплайн меток конверсия атрибутируется до 7 дней
показы 18% сессий не дошли до выдачи
Назовите причины такого разрыва и порядок, в котором вы будете их проверять.
Перебирайте механически — training-serving skew и занулённые признаки, утечка или устаревший холдаут офлайн, метка, которую офлайн-метрика вознаграждает, а OEC не видит, выигрыш вне показанных слотов и разбавление. Затем прогоните логи на одной популяции.
- ✗Считать, что лучшая офлайн-метрика обязана рано или поздно проявиться онлайн
- ✗Сравнивать офлайн и онлайн на разных популяциях
- ✗Игнорировать разбавление сессиями, которые не увидели выдачу
- →Как зануление признаков на сервинге меняет выдачу, которую реально видит пользователь?
- →Почему семидневное окно атрибуции способно сделать четырнадцатидневный эксперимент плоским?
Разбор
Разрыв между офлайном и онлайном почти всегда раскладывается на пять классов причин, и проверять их дешевле в порядке от самых механических к самым содержательным.
ранжирует не той моделью, что оценивалась офлайн.
ROC-AUC на данных, которых production уже не видит.
порядка вне показанных слотов в OEC не попадает.
на затронутых пользователях делится на всю группу.
- Training-serving skew. Занулённые 4 признака из 37 при скоринге означают, что production
- Испорченный офлайн-замер. Утечка или устаревший холдаут двухнедельной давности завышают
- Метрика не та. ROC-AUC меряет порядок пар, а решение стоит на CTR и выручке — улучшение
- Разбавление. 18% сессий вообще не дошли до выдачи, но попали в знаменатель, поэтому эффект
- Окно атрибуции. Конверсия доезжает до 7 дней, а тест шёл 14 — хвост обрезан.
Главный инструмент — реплей production-логов офлайн, чтобы сравнить обе метрики на одной популяции:
exposed = logs[logs.reached_ranked_list] # убираем разбавление
served = exposed.features_served # ровно то, что видел сервинг, с занулениями
offline_auc = roc_auc_score(exposed.label, model.predict(served))
online_ctr = exposed.groupby(exposed.variant).click.mean()
# если offline_auc на exposed падает до production-уровня — виноват skew, а не эксперимент