Дизайн A/B-теста
A/B - рабочая лошадь продуктового DS, и на собесе почти всегда просят продизайнить тест целиком - гипотезу, метрики, сплит, сроки. Валят стабильно на двух вещах - юнит рандомизации и расхождение фактического сплита с плановым. Обе всплывают только у тех, кто запускал тесты руками, поэтому их и спрашивают.
Типовые формулировки: «продизайнь тест новой кнопки», «как посчитаешь длительность?», «сплит вышел 48 на 52, это нормально?».
// Каркас ответа выучи как стихотворение: гипотеза, метрики, юнит рандомизации, минимальный эффект, размер выборки, длительность. Он закрывает вопрос почти в любой формулировке, надо только подставить детали задачи.
Всё решается до запуска
Гипотеза формулируется так, чтобы её можно было опровергнуть числом: «новая кнопка поднимет конверсию в оплату минимум на 3 процента», а не «улучшит пользовательский опыт». Второе нельзя ни подтвердить, ни опровергнуть, значит тестировать нечего.
Метрик две категории. Целевая - одна, названа заранее. Guardrail - метрики-предохранители, которые нельзя уронить ради целевой: время ответа, жалобы, отписки, отток. Их не улучшают, за ними следят.
MDE (minimum detectable effect) - минимальный эффект, который тест обязан заметить. Берётся из бизнеса: какой прирост вообще окупает разработку, поддержку и риск. Из MDE считают размер выборки, а не наоборот. Подход «сколько у нас трафика, такой MDE и запишем» - это способ договориться с собой, а не расчёт.
// После старта ничего из перечисленного не меняется. Поменял целевую метрику на середине - результат стал нечитаемым: теперь никто не отличит, что было решено до данных, а что подобрано под них.
- guardrail
- метрика-ограничитель. Выиграть целевую и уронить guardrail считается проигрышем, а не разменом
Юнит рандомизации: что именно ты делишь
Юнит рандомизации - то, что раскидывается по группам: юзер, сессия, устройство, город, водитель. Юнит анализа - то, по чему считается метрика. Правило: юнит рандомизации не может быть мельче юнита анализа.
Почему это не формальность. Делим юзеров, а метрику считаем по сессиям - и статистика ломается. Сессии одного человека похожи между собой, значит наблюдения зависимы, значит настоящей информации в выборке меньше, чем строк. Формула же считает дисперсию по числу строк, занижает её, и p-value выходит красивее, чем заслужено. Тест «прокрашивается» на пустом месте.
Если метрика всё-таки сессионная, дисперсию считают иначе: бутстрэпом по юзерам (пересэмплируем людей целиком, вместе со всеми их сессиями) или дельта-методом, который умеет считать разброс для метрик-отношений.
// Механика сплита: берётся хеш от пары «идентификатор юзера плюс соль эксперимента». Хеш детерминирован, поэтому человек видит свой вариант при каждом заходе. Соль у каждого теста своя - иначе попавшие в группу A в одном эксперименте окажутся в A и в следующем, и параллельные тесты начнут просачиваться друг в друга.
- соль
- строка, подмешиваемая в хеш, чтобы одно и то же значение давало разный результат в разных экспериментах
A/A-тест и разъехавшийся сплит
A/A-тест: обе группы получают одно и то же. Прокраситься не должно ничего. Если прокрасилось - сломана инструментация, сплит или сама процедура анализа, и хорошо, что ты узнал об этом до решения на миллион, а не после.
SRM (sample ratio mismatch) - расхождение фактического соотношения групп с плановым. Планировали 50 на 50, получили 48 на 52. Выглядит мелочью, проверяется тестом хи-квадрат, и вот честные числа: на тысяче юзеров такой перекос легко объясняется случайностью, p около 0.21. На десяти тысячах уже нет, p около 0.00006. На ста тысячах вероятность случайно получить такое расхождение исчезающе мала.
Хи-квадрат тут делает простую вещь: сравнивает наблюдаемые количества с ожидаемыми и отвечает, насколько удивительно такое расхождение при честном сплите. Читается как обычный p-value.
// Живой SRM означает, что рандомизация или сбор данных сломаны: бот попал в одну группу, часть событий потерялась на одном из вариантов, редирект отвалился. Такой тест выбрасывается целиком - починить его анализом нельзя, потому что неизвестно, кто именно потерялся и чем он отличался от оставшихся.
Сколько держать тест
Даже если нужное число пользователей набралось за два дня, тест держат минимум один полный недельный цикл, а лучше два. Причина простая: будни и выходные - это разные люди с разным поведением, и эксперимент, закончившийся в четверг, измерил только рабочую неделю.
Второе - эффект новизны. Первые дни люди тыкают в новое просто потому, что оно новое; всплеск потом спадает. Решение принимают по стабилизировавшемуся хвосту, а не по пику первого дня.
Если срок выходит неприемлемым, честных рычагов ровно два: поднять MDE до реального бизнес-порога либо снизить дисперсию метрики - CUPED (controlled experiment using pre-experiment data), стратификация, более чувствительная метрика. Нечестный рычаг - ослабить уровень значимости или мощность; он ускоряет тест ровно настолько же, насколько делает вывод ненадёжным.
// Отдельная категория, требующая специальной обработки: метрики-отношения вроде CTR (click-through rate) и метрики с тяжёлым хвостом вроде выручки на пользователя. Обычная формула дисперсии для них не годится, нужен дельта-метод или бутстрэп.
Как отвечать: «Как посчитаешь длительность A/B-теста?»
Из четырёх входов. MDE - минимальный эффект, который окупает внедрение, его беру у продакта, а не из головы. Базовое значение метрики и её дисперсия - из исторических данных. Уровень значимости обычно 0.05, мощность 0.8. Отсюда получается размер выборки на группу; делю на дневной приток пользователей и получаю дни. Дальше два округления из практики: вверх до полных недель, потому что будни и выходные ведут себя по-разному, и запас на эффект новизны, чтобы решать по стабилизировавшемуся хвосту. Порядок величин полезно держать в голове: при базовой конверсии 5 процентов ловить относительный прирост в 10 процентов - это примерно тридцать тысяч человек на группу. И считать длительность задним числом, по факту прокраса, нельзя - это подгонка под желаемое.
Названы все входы формулы, оба округления и живой порядок величин. Последняя фраза закрывает встречный вопрос про раннюю остановку до того, как его успели задать.
На чём валят
- −Считать размер выборки после запуска, «по факту» - это подгонка, а не планирование.
- −Рандомизировать юзеров, а считать по сессиям как по независимым наблюдениям: p-value занижен, тест прокрашивается сам собой.
- −Одна соль хеша на все эксперименты - группы коррелируют между тестами, результаты перетекают.
- −Отмахнуться от сплита 48 на 52: на большом трафике это сломанная рандомизация, а не округление.
- −Менять целевую метрику по ходу теста и потом объяснять, почему так и было задумано.
Проверьте себя
Пять вопросов из банка по этой подтеме. Всего их 18, остальные разбираются в тренажёре.
- Что такое MDE (minimum detectable effect) в дизайне A/B-теста?A)Максимально возможный эффект, который тест способен зафиксировать при выборкеB)Наименьший эффект, который тест надёжно поймает при данных n, α и мощностиC)Минимальное число дней, которое обязан длиться экспериментD)Минимально допустимый уровень значимости p-value для приёмки результата
показать ответ и разбор
+B)Наименьший эффект, который тест надёжно поймает при данных n, α и мощности// разбор: MDE — наименьший истинный эффект, который тест способен обнаружить с заданной мощностью при выбранных α и размере выборки. Он задаётся до старта из бизнес-соображений (какой аплифт вообще стоит ловить) и через power analysis определяет нужный размер выборки: меньше MDE — кратно больше n.
- Хотим ловить эффект вдвое меньше прежнего (MDE снизили в 2 раза) при той же значимости и мощности. Что с размером выборки?A)Размер выборки останется примерно прежним, ведь минимальный детектируемый эффект почти не влияет на его расчёт на практикеB)Нужно примерно вчетверо больше: размер выборки растёт как 1/MDE², так что половинный эффект учетверяет выборкуC)Достаточно увеличить выборку ровно вдвое, поскольку минимальный детектируемый эффект и объём выборки строго обратно пропорциональныD)Выборку, наоборот, можно уменьшить вдвое, потому что для меньшего эффекта по определению требуется меньше данных для обнаружения
показать ответ и разбор
+B)Нужно примерно вчетверо больше: размер выборки растёт как 1/MDE², так что половинный эффект учетверяет выборку// разбор: Размер выборки на группу при фиксированных α и мощности растёт обратно квадрату детектируемого эффекта: n ∝ σ²/MDE². Значит, чтобы поймать вдвое меньший эффект, нужно примерно в четыре раза больше наблюдений (и, соответственно, дольше тест). Отсюда практический вывод: гоняться за крошечными эффектами дорого — либо снижают дисперсию (CUPED, стратификация), либо принимают больший MDE.
- В A/B берут двусторонний критерий, хотя «мы же хотим только рост». Почему не односторонний?A)Односторонний критерий запрещён в статистике и не применяется на практике в экспериментахB)Двусторонний ловит и неожиданное падение метрики; односторонний удваивает риск проглядеть значимый вред от измененияC)Разницы между ними нет: односторонний и двусторонний тесты на данных дают идентичный p-valueD)Односторонний критерий требует ровно вдвое большей выборки, чем двусторонний, поэтому его на практике и избегают из экономии
показать ответ и разбор
+B)Двусторонний ловит и неожиданное падение метрики; односторонний удваивает риск проглядеть значимый вред от изменения// разбор: Односторонний тест смотрит только в одну сторону (рост), и если изменение неожиданно НАВРЕДИЛО, он это упустит — а в проде важно поймать и вред (guardrail). Двусторонний контролирует ошибку в обе стороны и потому по умолчанию безопаснее для продуктовых решений. Односторонний даёт чуть больше мощности при меньшей выборке, но ценой слепоты к вреду и соблазна «подкрутить» гипотезу постфактум. Он не запрещён, но применяют его осознанно.
- A/B на выходных дал +5%, в будни эффект пропадает. Как избежать ложных выводов из-за времени?A)Просто останавливать тест в тот самый момент, когда p-value впервые опустился ниже 0.05, вообще не глядя на дни неделиB)Запускать тест ровно на 3 дня — этого срока достаточно для продуктовой метрики и аудиторииC)Гонять тест в будни, исключив выходные как аномальные и нерепрезентативные дни для оценки эффектаD)Прогонять тест целым числом недель, чтобы охватить недельную сезонность (будни/выходные) поровну в обеих группах
показать ответ и разбор
+D)Прогонять тест целым числом недель, чтобы охватить недельную сезонность (будни/выходные) поровну в обеих группах// разбор: Поведение пользователей сильно завязано на день недели (будни vs выходные) и события; тест на неполной неделе или с перекосом дней смешивает эффект изменения с недельной сезонностью. Поэтому эксперимент гоняют целым числом недель (обычно ≥1-2), чтобы обе группы одинаково захватили все дни. Ранняя остановка по первому «значимому» p-value ломает гарантии, фиксированные «3 дня» произвольны, а выкидывать выходные — терять часть аудитории.
- Тестируем сразу 5 вариантов против контроля и берём лучший значимый. Что с этим не так?A)Множественные сравнения: с ростом числа вариантов растёт шанс ложного «победителя» — нужна поправка (Bonferroni и др.)B)Ничего страшного: чем больше вариантов протестировать за один раз, тем в итоге надёжнее и точнее оказывается выбор лучшего из нихC)Проблема лишь в том, что 5 вариантов требуют ровно в 5 раз МЕНЬШЕЙ выборки на каждый вариант, а не большей, как многие думаютD)Не получится тестировать больше двух вариантов сразу — статистически корректные A/B/n-тесты попросту не выходят в природе
показать ответ и разбор
+A)Множественные сравнения: с ростом числа вариантов растёт шанс ложного «победителя» — нужна поправка (Bonferroni и др.)// разбор: Сравнивая 5 вариантов с контролем на уровне 0.05 каждый, вы делаете 5 проверок, и вероятность хотя бы одного ложноположительного заметно выше 5% — «лучший значимый» может выиграть случайно (множественные сравнения, как при подглядывании). Нужна поправка на множественность (Bonferroni, Holm, контроль FDR) или заранее большая выборка на вариант. A/B/n-тесты возможны, но выборки требуют больше, а не меньше.
дальше
Теорию прочитали. Навык ставится повторением
В Сеньорчике эта подтема идёт в ежедневных сессиях: движок возвращает её, пока ответы не станут уверенными, и ведёт прогресс отдельно по каждой подтеме. Теория внутри тоже бесплатна, лимит только на количество вопросов в день.