Часть I · Постановка и измерение · глава 4 из 19
Валидация и эксперимент
Метрику посчитать легко, поверить ей трудно. Случайный сплит завышает качество через признаки, которых вы не подозревали; офлайн и онлайн расходятся систематически; A/B требует больше трафика, чем кажется, а привычка заглядывать в результаты превращает пять процентов ложных срабатываний в двадцать один. Всё это считается заранее — и здесь посчитано.
- Сплит только временной. При случайном таргет протекает через любой признак, проксирующий популярность: счётчик уже содержит будущие клики.
- Бейзлайн популярности обязателен. Не как соперник, а как измерительный прибор: он показывает, сколько метрики даётся вообще без персонализации.
- Вдвое меньший эффект — вчетверо больше данных. Проверено численно: отношение 3.98. Поэтому «давайте померим +0.1%» обычно означает «нам не хватит трафика».
- Подглядывание ломает уровень значимости. Одна проверка в конце — честные 5.0%, ежедневная за две недели — 21.5% ложных срабатываний на A/A-тесте.
1. Сплит
Почему единственный честный сплит — временной
Аргумент простой и работает всегда. В любом реальном датасете есть признаки, так или иначе проксирующие популярность: счётчик показов, число покупок, средний рейтинг, «сколько раз добавили в избранное».
При случайном сплите часть взаимодействий одного и того же айтема попадает в трейн, часть — в тест. Но признак «число покупок» посчитан по всем данным, включая тестовые. Значит, он уже содержит информацию о том, что произойдёт в тесте.
Модель этим пользуется — и совершенно правомерно с точки зрения оптимизации: признак информативен. Просто в проде такого признака не существует, потому что будущее ещё не наступило.
Утечка тем коварнее, что не выглядит утечкой: вы не подмешивали таргет в признаки руками, вы просто посчитали агрегат по всему датасету. И заметить это по метрикам нельзя — они как раз выглядят прекрасно.
Правильно: выбрать глобальную отсечку по времени \(T\), обучаться на всём до неё, проверяться на всём после. Все агрегаты и счётчики тоже считаются только по данным до \(T\) — это отдельная дисциплина, о которой легко забыть.
Схема «убрать у каждого пользователя последнее взаимодействие в тест» популярна в академических статьях и выглядит временной. Но отсечка у каждого пользователя своя, а значит для одного пользователя тестовый момент лежит в прошлом другого — и агрегаты снова текут.
Это одна из известных методологических проблем сравнения рекомендательных моделей в литературе: часть опубликованных приростов не воспроизводится именно из-за протокола, а не из-за моделей.
Решение про холодных надо принять явно
После временного сплита в тесте неизбежно окажутся пользователи и айтемы, которых не было в обучении. Что с ними делать — решение, а не деталь реализации, и от него сильно зависит число.
| Вариант | Что измеряет | Чем плох |
|---|---|---|
| выбросить холодных из теста | качество на знакомой аудитории | завышает: в проде холодные есть всегда, и их доля растёт |
| оставить и считать промахом | честное сквозное качество | смешивает две разные проблемы — качество модели и покрытие холодного старта |
| считать отдельно две метрики | обе величины по отдельности | дороже, но это единственный вариант, по которому можно принимать решения |
Третий вариант и рекомендуется: одна метрика на тёплых, вторая на холодных, и доля холодных как отдельное число. Иначе улучшение модели и ухудшение покрытия смешиваются в одно движение.
2. Бейзлайн, без которого нельзя
Прежде чем сравнивать модели между собой, нужно сравнить их с отсутствием модели. Бейзлайн — топ популярного за окно.
Бейзлайн популярности отвечает на вопрос, сколько метрики набирается вообще без персонализации. Ответ обычно неприятно высокий — и именно поэтому его надо знать.
- Если ваша модель обходит популярность на проценты, вопрос «а стоит ли она своей сложности» становится содержательным.
- Если не обходит вовсе — почти наверняка ошибка в протоколе, а не в модели.
- Если обходит подозрительно сильно — ищите утечку. Слишком хороший результат на первом прогоне это симптом, а не успех.
И тот же приём применяется к любой новой стадии: прежде чем добавлять источник кандидатов, посмотрите, что даёт «взять больше из существующего».
3. Почему офлайн и онлайн расходятся
Разрыв между офлайн-метрикой и результатом A/B — не аномалия, а норма, и причины у него системные.
| Причина | Механизм |
|---|---|
| Офлайн меряется на чужой политике | отложенная выборка собрана прошлой системой. Новая модель предлагает другое, и как на это отреагируют, в логах не написано |
| Метрика — прокси | NDCG растёт, удержание не двигается: они связаны, но не одно и то же |
| Позиционное смещение в разметке | офлайн модель хвалят за воспроизведение прошлого порядка, включая его смещения |
| Продуктовые эффекты вне модели | скорость ответа, вёрстка, доля рекламы — в офлайне их нет вовсе |
| Новизна и привыкание | всплеск в первые дни на новизне и откат потом; офлайн не видит времени |
Практический вывод не «офлайн бесполезен», а «офлайн — фильтр». Он дёшево отсеивает заведомо плохое; решение принимает эксперимент. Держать между ними связь помогает простая привычка: записывать офлайн-прогноз до запуска и потом сверять. Через десяток экспериментов вы узнаете переводной коэффициент своей системы, и это ценнее любой отдельной метрики.
4. Сколько нужно трафика
Главная арифметика перед экспериментом: хватит ли данных, чтобы вообще различить эффект, который вы надеетесь получить.
Для доли (конверсия, CTR) при уровне значимости 5% и мощности 80%:
$$ n \;=\; \frac{\Bigl(z_{\alpha/2}\sqrt{2\bar p(1-\bar p)} \;+\; z_{\beta}\sqrt{p_0(1-p_0) + p_1(1-p_1)}\Bigr)^2}{(p_1 - p_0)^2} $$где \(p_0\) — базовая конверсия, \(p_1\) — ожидаемая, \(\bar p\) — их среднее. Важно тут не запомнить формулу, а увидеть знаменатель: \(n\) обратно пропорционально квадрату абсолютной разницы.
| Базовый CTR | прирост 1% | прирост 2% | прирост 5% |
|---|---|---|---|
| 1% | 15.6 млн | 3.9 млн | 637 тыс |
| 5% | 3.0 млн | 753 тыс | 122 тыс |
| 20% | 630 тыс | 158 тыс | 26 тыс |
На группу; \(\alpha = 5\%\), мощность 80%. Числа воспроизводятся скриптом _tools/abtest_demo.py.
Два наблюдения, которые стоит унести:
- Закон вчетверо. При базе 5% прирост 2% требует 753 тысяч, прирост 1% — 3.0 млн. Отношение 3.98: вдвое меньший эффект стоит вчетверо больше данных. Это и есть ответ на предложение «померить плюс одну десятую процента».
- Чем реже событие, тем дороже. При том же относительном приросте падение базовой конверсии с 20% до 1% увеличивает требуемую выборку в 25 раз, потому что абсолютная разница \(p_0 \cdot \text{lift}\) стала меньше.
Обычно трафик задан, и полезнее спросить, какой минимальный эффект вы вообще способны различить. При базовом CTR 5%:
| Наблюдений на группу | Различимый прирост от |
|---|---|
| 100 тыс | 5.53% |
| 1 млн | 1.73% |
| 10 млн | 0.55% |
Считать MDE надо до запуска. Эксперимент, у которого MDE выше ожидаемого эффекта, не «покажет отсутствие эффекта» — он не покажет ничего, и это будет стоить двух недель.
Подглядывание
Соблазн понятный: тест идёт, дашборд обновляется, и хочется посмотреть, не покрасилось ли уже. Проблема в том, что уровень значимости 5% относится к одной проверке.
Симуляция, в которой обе группы устроены одинаково, то есть истинный эффект строго нулевой. Считаем, в какой доле экспериментов критерий хоть раз пересёк порог:
| Как смотрим | Ложных срабатываний |
|---|---|
| один раз в конце | 5.0% |
| раз в день, неделя | 16.5% |
| раз в день, две недели | 21.5% |
20 000 повторений на конфигурацию; _tools/abtest_demo.py.
Каждый новый взгляд — ещё один шанс случайно пересечь порог. Номинальные 5% превращаются в 21%, то есть каждый пятый «успешный» эксперимент на самом деле пустой.
- Фиксировать горизонт заранее и смотреть один раз в конце. Скучно и работает.
- Последовательные критерии (SPRT, always-valid inference) — если смотреть по ходу действительно нужно. Они устроены так, что подглядывание разрешено по построению, ценой чуть большей выборки.
- Alpha spending — заранее расписанный бюджет значимости по заранее назначенным точкам проверки.
Отдельно: остановка «как только покрасилось» — это подглядывание в самой вредной форме, потому что она систематически завышает оценку эффекта. Вы останавливаетесь на случайном максимуме.
- Вкладка размера выборки: кривая падает как \(1/\sqrt{n}\). Чтобы различить вдвое меньший эффект, нужно вчетверо больше данных.
- Уменьшите базовую конверсию при том же относительном приросте — требуемая выборка растёт, потому что абсолютная разница стала меньше.
- Вкладка подглядывания — это A/A-тест. Увеличивайте число проверок и смотрите, как доля ложных срабатываний уходит от 5% к 20 с лишним.
Что сказать на собесе: «Горизонт фиксируем заранее и считаем MDE до старта. Если надо смотреть по ходу — последовательный критерий или alpha spending, иначе номинальные 5% превращаются в 20 с лишним».
5. Когда рандомизация по пользователям ломается
Классический A/B предполагает изоляцию: то, что происходит в тесте, не влияет на контроль. В рекомендательных системах это предположение нарушается регулярно.
| Где ломается | Механизм | Чем чинят |
|---|---|---|
| Двусторонние рынки такси, маркетплейс, доставка |
тестовая группа выкупает ограниченный ресурс — курьеров, товар на складе, — и контролю достаётся меньше | рандомизация по городам, дарксторам, временным слотам; switchback-тесты |
| Социальные графы | пользователь из теста активнее постит и лайкает, это видят его друзья из контроля | кластерная рандомизация по компонентам графа |
| Общие модели | система переобучается на логах обеих групп, и тестовая политика подмешивает свои данные в обучение — контроль перестаёт быть контролем | раздельное обучение на данных контроля либо холдаут, исключённый из обучения |
Третий случай особенно неприятен тем, что незаметен: инфраструктура A/B работает штатно, разметка корректна, а утечка идёт через переобучение. Проверяется вопросом «а на чьих логах учится модель, которую видит контроль».
6. Дисциплина эксперимента
Если список метрик широкий, вы всегда найдёте что-то, что покрасилось. При двадцати метриках и уровне 5% одна ложно-значимая ожидается просто по построению.
Поэтому до старта фиксируются: конкретная проверяемая гипотеза, одна главная метрика решения, горизонт и правило остановки. Всё остальное — вспомогательные срезы для понимания, а не основания для выката.
К каждой метрике роста полезно завести метрику, которая испортится, если рост достигнут неправильным способом.
- растёт CTR — смотрим на глубину просмотра и долю быстрых возвратов;
- растёт время в приложении — смотрим на удержание через неделю;
- растёт GMV — смотрим на возвраты и на долю показов у топ-1% каталога;
- растёт любая метрика — смотрим на coverage: не куплен ли рост схлопыванием в популярное.
Это тот же приём, что и в главе про контур: быстрые метрики двигают, медленные и антагонистичные — охраняют.
Вопросы с собеседований
Почему нельзя делать случайный сплит?
Потому что в данных почти наверняка есть признаки, проксирующие популярность: счётчики показов, покупок, средний рейтинг. При случайном сплите они посчитаны по всему датасету, включая тест, и уже содержат будущие клики. Модель этим пользуется, метрики выглядят прекрасно, а в проде такого признака не существует.
Правильно — глобальная отсечка по времени, причём все агрегаты и счётчики тоже считаются только по данным до неё, иначе временной сплит перестаёт быть временным.
Leave-one-out выглядит временным, но отсечка у каждого пользователя своя, поэтому агрегаты снова текут. Это известная методологическая проблема академических сравнений.
Что делать с холодными пользователями и айтемами в тестовой выборке?
Принять решение явно, потому что от него сильно зависит число. Выбросить холодных — завысить качество: в проде они есть всегда. Оставить и считать промахом — честно, но смешивает качество модели с покрытием холодного старта.
Рабочий вариант — считать две метрики отдельно, на тёплых и на холодных, плюс долю холодных как самостоятельное число. Иначе улучшение модели и ухудшение покрытия сливаются в одно движение метрики.
Зачем нужен бейзлайн популярности, если он заведомо хуже?
Он не соперник, а измерительный прибор: показывает, сколько метрики набирается вообще без персонализации. Ответ обычно неприятно высокий.
Дальше он читается как диагностика. Модель обходит популярность на проценты — вопрос о её сложности становится содержательным. Не обходит вовсе — почти наверняка ошибка в протоколе. Обходит подозрительно сильно — ищите утечку: слишком хороший результат на первом прогоне это симптом, а не успех.
Сколько трафика нужно, чтобы поймать прирост в 1%?
Зависит от базовой конверсии, и зависимость квадратичная по абсолютной разнице. При базовом CTR 5% и стандартных 5% значимости с мощностью 80% — около 3 млн наблюдений на группу. При CTR 1% — 15.6 млн. При CTR 20% — 630 тысяч.
Ключевое соотношение: вдвое меньший эффект требует вчетверо больше данных (проверено численно: 753 тыс против 3.0 млн, отношение 3.98). Поэтому предложение «померить +0.1%» обычно означает «нам не хватит трафика», и это надо посчитать до запуска, а не после.
Почему нельзя подглядывать в результаты A/B по ходу?
Уровень значимости 5% относится к одной проверке. Каждая следующая — ещё один шанс случайно пересечь порог.
На A/A-тесте, где истинный эффект строго нулевой: одна проверка в конце даёт честные 5.0% ложных срабатываний, ежедневная проверка в течение недели — 16.5%, в течение двух недель — 21.5%. То есть каждый пятый «успешный» эксперимент пустой.
Что делать: фиксировать горизонт заранее; либо брать последовательный критерий или alpha spending, где подглядывание разрешено по построению. И отдельно — остановка «как только покрасилось» систематически завышает оценку эффекта, потому что останавливаются на случайном максимуме.
Когда рандомизация по пользователям даёт смещённую оценку?
Когда нарушается изоляция групп. Три типичных случая.
Двусторонние рынки: тестовая группа выкупает ограниченный ресурс — курьеров, товар, — и контролю достаётся меньше. Лечится рандомизацией по городам, дарксторам или временным слотам, switchback-тестами.
Социальные графы: активность теста видят друзья из контроля. Лечится кластерной рандомизацией по компонентам графа.
Общие модели: система переобучается на логах обеих групп, и тестовая политика подмешивает данные в обучение — контроль перестаёт быть контролем. Самый незаметный случай, потому что инфраструктура при этом работает штатно.
Шпаргалка одним экраном
Сплит
Только временной, одна глобальная отсечка. Агрегаты — тоже слева от неё. Leave-one-out течёт.
Холодные в тесте
Две метрики отдельно плюс доля холодных. Иначе качество и покрытие сливаются.
Бейзлайн
Популярность — прибор, а не соперник. Слишком хороший результат — симптом утечки.
Размер выборки
При CTR 5%: +5% → 122 тыс, +2% → 753 тыс, +1% → 3.0 млн. Вдвое меньше эффект — вчетверо больше данных.
Подглядывание
1 проверка — 5.0%, ежедневно две недели — 21.5%. Горизонт фиксируем заранее.
Сетевые эффекты
Ресурс, граф, общая модель. Лечение: кластерная рандомизация, switchback, холдаут вне обучения.
Первоисточники
- R. Kohavi, D. Tang, Y. Xu. Trustworthy Online Controlled Experiments, Cambridge University Press 2020 — практическая база по A/B: мощность, подглядывание, типичные ошибки.
- R. Johari, P. Koomen et al. Always Valid Inference: Continuous Monitoring of A/B Tests — критерии, при которых смотреть по ходу можно.
- M. Saveski, J. Pouget-Abadie et al. Detecting Network Effects: Randomizing Over Randomized Experiments, KDD 2017 — как ловят нарушение изоляции.
- M. F. Dacrema, P. Cremonesi, D. Jannach. Are We Really Making Much Progress?, RecSys 2019 — про воспроизводимость и роль протокола сравнения.
- Числа главы:
_tools/abtest_demo.pyв этом репозитории.