A/B-тестирование: как провести тест от гипотезы до решения
Пошаговый A/B-тест на учебной игре: гипотеза, метрика, MDE, сплит, D7 retention, интервал и решение. Где ломается сравнение и что проверить до раскатки.
Содержание статьи
Продакт предлагает заменить короткий онбординг длинным туториалом. До релиза неизвестно, удержит ли это новичков или заставит их уйти раньше. A/B-тестирование назначает новым игрокам старый и новый вариант параллельно, заранее выбирает метрику и правило остановки, а после полного наблюдения сравнивает результат. Разберём весь путь на вымышленной учебной игре DragonKeep: там есть улучшение D7, скидка с непроверенной ценой и A/A со сломанным сплитом.
Коротко: что такое A/B-тест и какие решения принять заранее
A/B-тест — контролируемый эксперимент: подходящих пользователей случайно и устойчиво распределяют между текущим вариантом A и изменённым B. Обе группы живут в одни календарные дни. Если назначение, сбор событий и анализ выдержали проверки, разницу по выбранной метрике можно связывать с изменением продукта в пределах изученной аудитории. Сравнение «до запуска» и «после запуска» этого не умеет: вместе с интерфейсом меняются сезон, трафик и поведение старых пользователей.
До старта запишите, кого включать, какую метрику улучшить, какого изменения достаточно для решения, сколько пользователей и дней требуется и что остановит раскатку. После сбора проверьте назначение групп, окно наблюдения, эффект с интервалом и защитные показатели. Значимое p без этих проверок — число из процедуры, а не разрешение на релиз.
- Назовите изменение, аудиторию и измеримый результат до первого показа.
- Выберите основную метрику и показатели, которым нельзя заметно навредить.
- Задайте MDE, объём, срок и фиксированное правило анализа.
- Проверьте назначение и доставку события до сравнения эффекта.
- Примите решение по интервалу и цене ошибки, затем наблюдайте раскатку.
Почему «до и после» не заменяет контрольную группу
Представьте, что D7 вырос после выпуска туториала. В ту же неделю закончилась дорогая рекламная кампания, и доля органических установок выросла. У органики удержание могло быть выше само по себе. В отчёте «до/после» эти два движения складываются; невозможно сказать, какую часть дал туториал. Параллельный контроль видит тот же календарь и похожий поток игроков. Рандомизация разносит известные и неизвестные признаки между группами в среднем и даёт более сильную основу для причинного вывода.
Контроль не делает эксперимент безошибочным. Если игроку назначили test на телефоне, а control на планшете, варианты смешаются. Если плохой экран мешает отправить событие экспозиции, в анализ попадут только выжившие пользователи. Если тест меняет поведение друзей игрока в контроле, возникает вмешательство между участниками. Каждая поломка меняет причинный вопрос, даже когда размеры групп похожи.
A/B не нужен для исправления критического бага, когда оставить часть людей на сломанной версии нельзя. Рандомизация может быть невозможна при правовом ограничении или сетевом эффекте. Тогда нужен отдельный дизайн причинной оценки; отсутствие эксперимента нельзя скрывать обычным сравнением двух месяцев.
| Подход | Что сравнивается | Главная опасность |
|---|---|---|
| До / после | разные люди и дни | сезон, каналы, параллельные изменения |
| A/B | случайно назначенные варианты в одни дни | ошибка назначения, логирования или взаимодействие групп |
Шаг 1. Гипотеза с механизмом и опровержением
Для DragonKeep рабочая гипотеза звучит так: «длинный туториал помогает новому игроку понять первые уровни и повышает долю вернувшихся на седьмой день». Изменение — длина и содержание онбординга, аудитория — новые установки с 15 августа по 30 сентября 2024 года, результат — D7 retention. Если разница слишком мала, неопределённа или куплена ухудшением оплаты, гипотеза не становится поводом для полного запуска.
Фраза «сделаем красивее, метрики вырастут» не задаёт механизм. В ней нет границы, после которой команда признала бы идею неудачной. До кода договоритесь, почему игрок должен вести себя иначе и какое наблюдение это опровергнет. В карточке эксперимента отдельно запишите дату, версию назначения и ответственного за решение. Это убережёт команду от переписывания истории после первого графика.
В учебной таблице experiments гипотеза обещает +3 п.п., а expected_mde_pp равен 1,5. Это разные строки: желаемый результат и минимальный интересующий эффект. Их нельзя незаметно поменять местами после завершения теста.
Шаг 2. Метрика и ограничения: какой выигрыш полезен
Основная метрика — D7: был ли у игрока сеанс ровно на седьмой календарный день после установки. Один человек даёт один бинарный исход, даже если в тот день открыл игру несколько раз. Знаменатель — все назначенные игроки группы, а не только завершившие туториал. Иначе новый экран сам отберёт «выживших», и метрика начнёт хвалить самый тяжёлый сценарий.
Для онбординга полезны ограничения: доля первой оплаты, доход на назначенного игрока за одинаковые 14 дней и технические ошибки входа. В учебных данных pay rate за 14 дней составляет 393/8 534 = 4,61% у control и 431/8 469 = 5,09% у test, доход на игрока — около 38,92 и 39,21 ₽. Эти наблюдения не заменяют заранее установленного порога вреда и оценки неопределённости. Они показывают, что перед раскаткой нужны данные для проверки защитных метрик.
Метрику выбирают под решение. Если скидка на стартовый пак чуть повышает покупку именно пака, но общий доход на назначенного игрока не растёт, основной результат нельзя читать в одиночку. Не назначайте десять равноправных «главных» исходов: любой случайно удачный станет оправданием релиза. Для выбора основной и защитных метрик есть отдельный разбор.
Уточните в карточке, что считается «днём семь». Здесь это ровно седьмой календарный день от install_date, а не любое возвращение в течение первой недели и не окно в 168 часов от первой сессии. Все три определения разумны для разных вопросов, но дадут разные числители. Аналитик должен записать таймзону, включённые события и обработку повторных сеансов до начала теста. После этого код сверяется с определением, а не наоборот.
Шаг 3. MDE, выборка и срок до запуска
MDE отвечает на вопрос «какой эффект достоин обнаружения при разумной длительности». В onboarding_v2 записано 1,5 процентного пункта D7. При исходных примерно 13,36% разница в 1,5 п.п. означает новый уровень около 14,86%, а не «плюс полтора процента». Планировать выборку после того, как известен ответ, нельзя: команда подгонит условие победы под результат.
Размер группы растёт примерно обратно квадрату интересующей абсолютной разницы. Если захотеть видеть вдвое меньший эффект при той же мощности и базовом уровне, потребуется примерно вчетверо больше наблюдений. Конкретный объём можно пересчитать в калькуляторе выборки, но в него нужно подать содержательный MDE, а не число, которое обещает удобную дату релиза.
Срок должен вместить набор участников и полный горизонт исхода. Последний игрок, увидевший туториал 30 сентября, даст D7 только 7 октября. Остановить анализ 30 сентября — значит наказать последние когорты за то, что календарь ещё не дошёл до их седьмого дня. Выборка и длительность фиксируются вместе; трафик гуляет по дням недели, поэтому полезен полный недельный цикл.
Оценка трафика тоже требует осторожности. Число установок за прошлый месяц не равно числу независимых пользователей, которых можно назначить в следующем: меняются каналы привлечения, рекламный бюджет, фильтры участия и доля несовершеннолетних или повторных установок. Если трафика не хватает, честно пересмотрите длительность или бизнес-порог до запуска. Не собирайте «недостающий» объём за счёт нескольких устройств одного игрока: это добавит строки, но не ту независимую информацию, на которой основан расчёт мощности.
| Поле | DragonKeep | Зачем до запуска |
|---|---|---|
| Аудитория | новые установки 15.08–30.09 | один тип пользователя |
| Основной исход | D7: сеанс через 7 дней | не выбирать метрику постфактум |
| MDE | +1,5 п.п. | оценить практический масштаб |
| Анализ | после дозревания последнего D7 | не обрезать поздние когорты |
Шаг 4. Один игрок — один вариант
В генераторе учебной базы вариант назначается стабильным хэшем пары user_id|exp_id. Для onboarding_v2 получилось 8 534 в control и 8 469 в test. Назначение хранится в exposures.variant, дата экспозиции совпадает с датой установки. Это зерно анализа: одна строка — один игрок в данном эксперименте. Повторные сеансы не становятся новыми участниками.
В users есть колонка ab_group, но она относится к общей разметке датасета и не является назначением трёх исторических тестов. Для онбординга она расходится с exposures.variant почти у половины игроков. JOIN по user_id допустим для даты установки и платформы, но итоговую группу берите только из exposures. Иначе реальный эффект можно разбавить и ошибочно признать отсутствие результата.
В рабочем продукте единица назначения зависит от механизма: пользователь, аккаунт, магазин или кластер друзей. Если изменение влияет на общую корзину семьи, случайное назначение отдельных устройств создаст переплетение вариантов. Правило идентификации и стабильности должно лежать рядом с гипотезой, а проверка дублей — запускаться до анализа метрик.
Шаг 5. A/A и SRM: сначала проверка измерения
A/A показывает обеим группам одно и то же и проверяет назначение, доставку экспозиции, логирование исхода и расчёт. Учебный menu_color задуман как такой тест: эффекта на сеансы в генераторе нет. Но флаг настроен на 54/46 вместо обещанных 50/50: в exposures 10 929 control и 9 350 test. χ² около 122,95, p около 1,4 × 10⁻²⁸ для плана 50/50. На таком сигнале нельзя «поправить коэффициентом» итог и объявить платформу исправной.
Для онбординга тоже сверяют размер групп с планом, затем долю потерь экспозиции, задержки доставки, версию приложения и полноту сеансов. Равный общий сплит не исключает поломку в одном сегменте. При SRM поиск эффекта останавливают, пока не найден механизм ошибки; иначе сравнивают разные популяции вместо двух вариантов одного эксперимента.
A/A не доказывает, что будущий A/B получится качественным при другой аудитории и метрике. Он проверяет конкретный путь данных. После исправления флага повторите A/A и добавьте автоматический контроль сплита в запуск, чтобы ошибка не вернулась после следующего релиза.
Шаг 6. Соберите D7 без умножения игроков на сеансы
В sessions.csv один игрок может иметь много строк. D7 требует факта хотя бы одного сеанса на install_date + 7 days; соединение должно сохранять знаменатель из exposures. Генератор дополнительно записал 186 D7-сеансов test в extra_sessions_onboarding_v2.csv, не меняя основной sessions.csv. Для результата курса нужен союз обоих файлов, после которого повторные сеансы одного дня схлопываются по игроку.
Запрос ниже группирует по exposures.variant, присоединяет установку и проверяет наличие сеанса в объединённом источнике. Он возвращает 1 140 из 8 534 у control и 1 332 из 8 469 у test. Если забыть дополнительный файл, часть объявленного учебного эффекта исчезнет; если взять users.ab_group, ответите на другой вопрос. Сохраните рядом с отчётом оба контроля: число назначенных и число вернувшихся.
| Вариант | Назначено | Вернулись D7 | Доля |
|---|---|---|---|
| control | 8 534 | 1 140 | 13,36% |
| test | 8 469 | 1 332 | 15,73% |
SELECT e.variant, COUNT(DISTINCT e.user_id) AS exposed,
COUNT(DISTINCT CASE WHEN s.session_id IS NOT NULL THEN e.user_id END) AS returned_d7
FROM exposures e JOIN users u USING (user_id)
LEFT JOIN sessions_all s ON s.user_id = e.user_id
AND s.session_date = u.install_date + INTERVAL 7 DAY
WHERE e.exp_id = 'onboarding_v2'
GROUP BY e.variant ORDER BY e.variantШаг 7. Интервал и p-value отвечают на разные вопросы
Разница D7 равна +2,37 п.п. Для независимых долей 95%-й интервал разницы по нормальному приближению — от +1,31 до +3,43 п.п. Ноль вне интервала; двусторонний pooled z-тест даёт p около 0,000012. При условии отсутствия эффекта столь большой или больший разрыв встречался бы редко в модели теста. Это не вероятность того, что гипотеза верна, и не шанс «успеха» следующей раскатки.
Нижняя граница интервала ниже MDE 1,5 п.п. Точечная оценка выше MDE, но данные не доказали, что истинный выигрыш превышает этот практический порог. Если бизнес готов запускать при любом убедительном положительном эффекте и цена ошибки мала, можно перейти к поэтапной раскатке. Если заранее записано правило «нижняя граница выше 1,5», тест его не прошёл, несмотря на маленькое p.
Интервал относится к популяции, похожей на изученных новых игроков, и к D7. Он не охватывает ошибку логирования или смену рекламных каналов после эксперимента. Поэтому формула — только один слой доказательства, а не замена проверкам назначения и метрики.
(1 332 / 8 469 − 1 140 / 8 534) × 100 = +2,37 п.п.95%-й интервал [+1,31; +3,43] п.п.; MDE дизайна +1,5 п.п.
Высота — доля назначенных игроков с сеансом на седьмой день; эффект +2,37 п.п.
Пример A/B-теста: от карточки к записке продакту
Карточка DragonKeep содержит гипотезу о длинном туториале, аудиторию новых установок, D7 как исход и MDE 1,5 п.п. После назначения 17 003 игроков до полного D7 прошло минимум семь дней от последней установки. В итоговой таблице test выше control на 2,37 п.п.; интервал положителен, а точечный эффект больше MDE. Так выглядит пример, где числитель, знаменатель и срок названы до слова «победа».
Рекомендация менеджеру: расширять охват постепенно, наблюдая D7, оплату и ошибки входа на новых сегментах. Не обещать ровно +2,37 п.п. каждому будущему игроку: это оценка одного потока установок. До полного включения задайте автоматический порог отката и владельца решения. Если бизнесу обязательно доказать эффект больше 1,5 п.п. нижней границей интервала, текущих данных недостаточно: обсудите новый дизайн или продолжение набора, а не меняйте правило после результата.
Проверка после запуска отличается от повторного выбора победителя. На раскатке вы следите, не сломались ли технические и защитные показатели и не изменился ли состав трафика. Мониторинг не становится независимой репликацией старого эксперимента: аудитории и условия уже другие.
В рабочем паспорте полезно разделить три даты: начало назначения, конец назначения и конец наблюдения исхода. Если последний игрок установил игру 30 сентября, его D7 станет известен 7 октября; до этого итоговая строка ещё не дозрела. Раннее чтение допустимо для диагностики доставки и SRM, но не для произвольного объявления победы. Так команда не путает календарное завершение выдачи варианта с готовностью метрики.
План раскатки тоже часть решения. Можно начать с небольшой доли новых игроков, затем увеличить охват после проверки событий и guardrail. Такой запуск не обещает, что эффект останется точь-в-точь +2,37 п.п.; он проверяет переносимость результата и защищает от технического сбоя в масштабе. До релиза договоритесь, кто видит тревогу, какая величина ухудшения требует отката и где лежит неизменяемая итоговая выгрузка теста.
| Вопрос | Ответ для решения |
|---|---|
| Для кого | новые игроки, 15.08–30.09.2024 |
| Как мерили | D7 по назначению, с дополнительными сеансами |
| Результат | +2,37 п.п.; 95% ДИ [+1,31; +3,43] |
| Ограничение | нижняя граница ниже MDE; защитные пороги не зафиксированы |
| Действие | поэтапный запуск с мониторингом или донабор при строгом MDE-правиле |
Когда результат требует отказа, а не раскатки
Второй учебный тест снижал заявленную цену стартового пака с 129 до 99 ₽. В одинаковом 14-дневном окне доля первой покупки пака стала 125/8 622 = 1,45% вместо 117/8 690 = 1,35%, но интервал разницы пересекает ноль. Общая доля платящих, напротив, 4,44% против 4,63%; доход на назначенного игрока 32,85 ₽ против 35,33 ₽. Коммерческий выигрыш не установлен. Более того, в платежах пака видны суммы 129, 116,10 и 103,20 ₽, но нет 99 ₽. Доставку цены и выгрузку нужно проверить до любого вывода о скидке.
Третий учебный тест menu_color нельзя доводить до интерпретации эффекта: план 50/50 нарушен. Даже если среднее число сессий в группах близко, отсутствие заметной разницы не доказывает исправность назначения. Команда останавливает анализ, ищет причину SRM и повторяет проверку. Честным результатом бывает отказ от запуска или отказ доверять данным.
| Эксперимент | Что наблюдаем | Решение |
|---|---|---|
| onboarding_v2 | D7 +2,37 п.п., интервал выше нуля | поэтапно раскатить при согласованных ограничениях |
| starter_pack_99 | выигрыш не установлен; 99 ₽ в платежах нет | не раскатывать и проверить доставку цены |
| menu_color | 10 929 / 9 350 вместо 50/50 | считать результат недостоверным, исправить SRM |
Таблица процесса: где ошибаются
Процесс нужен для защиты каждого перехода: от идеи к метрике, от метрики к данным, от данных к решению. Сохраните таблицу рядом с паспортом эксперимента, чтобы не искать правило в день, когда результат уже нравится команде.
Опасна подмена единицы анализа. Рандомизировали пользователей, а потом проверили тысячи сеансов как независимые наблюдения — интервал сузится без новых участников. Для D7 один игрок даёт один исход, для выручки у игрока суммируются платежи за фиксированный горизонт. Таблица сеансов строит исход, но не становится списком новых людей.
| Шаг | Что сверить | Ошибка и цена |
|---|---|---|
| Гипотеза | изменение, механизм, аудитория | после теста выбирают удачную историю |
| Метрики | основная и ограничения | рост доли скрывает потерю дохода |
| Дизайн | MDE, n, срок, окно исхода | обрезают D7 поздних когорт |
| Назначение | стабильный вариант на пользователя | устройство или JOIN смешивает группы |
| Сбор | экспозиция и полнота исхода | исчезнувшие события создают ложный эффект |
| SRM | факт против плановой доли | сравнивают разные популяции |
| Анализ | эффект, интервал, защитные метрики | малое p принимают за полезность |
| Решение | правило релиза и мониторинг | обещают точный выигрыш всем будущим |
Ошибки, которые превращают эксперимент в рассказ
Первая — считать D7 только среди завершивших туториал: вариант меняет шанс попасть в знаменатель. Вторая — брать users.ab_group вместо exposures.variant: почти половина игроков меняет метку, эффект размывается. Третья — забыть дополнительный файл сеансов: часть созданных для учебного теста D7 исчезнет из числителя.
Четвёртая — остановить тест, когда p впервые стало меньше 0,05. При повторных взглядах без заранее выбранной последовательной процедуры вероятность ложного открытия выше заявленной. Пятая — объявить +2,37 п.п. гарантией: интервал включает меньшие эффекты, а состав следующего трафика неизвестен. Шестая — увидеть 54/46 в A/A и всё равно читать метрику: SRM указывает на нарушение входа в анализ.
Седьмая — сменить основную метрику скидочного теста на покупку конкретного пака, потому что она чуть лучше, игнорируя доход на игрока и отсутствие цены 99 ₽. Ошибка не в вычислении p, а в выборе результата после просмотра данных. Отдельный обзор ловушек включает множественные сравнения и сегменты, открытые только после теста.
Когда A/B провести нельзя
Иногда вариант нельзя выдать случайной половине: изменение затрагивает всех продавцов на общем рынке, касается безопасности или уже включено внешним подрядчиком. Тогда определите группы и периоды для сравнения и назовите альтернативные объяснения. Прерванный временной ряд, разность разностей и синтетический контроль требуют своих предпосылок; они не становятся A/B только потому, что таблица содержит колонки «контроль» и «тест».
Если рандомизация возможна, но требуемый эффект слишком мал для доступного трафика, честный ответ — тест не даст обещанную точность в нужный срок. Можно выбрать заранее обоснованную более чувствительную метрику, расширить период или принять решение по другим данным с большей неопределённостью. Нельзя назвать «не значимо» доказательством отсутствия полезного эффекта, когда интервал допускает выигрыш.
Для критического сбоя доступности не оставляйте контроль на неисправной версии ради статистической красоты. Зафиксируйте до и после, отслеживайте побочные эффекты и назовите предел причинного вывода.
Для сетевых продуктов случайное назначение отдельных пользователей иногда нарушает независимость: продавцы и покупатели встречаются в одном рынке, друзья видят действия друг друга, а изменение алгоритма влияет на общий запас внимания. Возможный выход — кластерное назначение по рынкам или временам, но тогда независимых единиц гораздо меньше, чем пользователей. Нельзя считать участников внутри кластера отдельными независимыми экспериментами только потому, что они дают отдельные строки в логах.
Частые вопросы и следующий шаг
«Сколько должен идти A/B-тест?» Пока не набраны рассчитанная выборка и полный исход последней когорты; универсальных «двух недель» нет. «Можно ли закончить раньше при p < 0,05?» Только если до старта выбран последовательный метод и его правила. «Нужен ли A/A перед каждым запуском?» Инфраструктуру проверяют постоянно; полноценный A/A полезен после изменений назначения и логирования.
«Что если интервал пересекает ноль?» Данные не различили ноль и некоторые изменения в пределах интервала; сравните границы с полезным и вредным масштабом. «Можно ли раскатить при значимом результате?» После проверки SRM, основной метрики, ограничений и цены ошибки — возможно; точечное значение будущему трафику не гарантируется.
Если у вас есть таблица групп и конверсий, попробуйте калькулятор значимости и проверку SRM. Для сырых экспозиций и сегментов есть A/B в SQL и симулятор аналитика. Следующий навык — написать итог как действие с границами неопределённости, а не как «p зелёный».
Материалы по теме

Результаты A/B-теста: как читать числа и принимать решение
Эффект, доверительный интервал, p-value, MDE и защитные метрики на двух экспериментах DragonKeep. Матрица решений и шаблон отчёта менеджеру.

A/A-тест: как проверить систему экспериментов до первого A/B
A/A-тест проверяет назначение, экспозиции и метрики до анализа эффекта. Учебный menu_color показывает SRM 54/46 при плане 50/50 и путь расследования.

Статистическая мощность: почему тест не находит эффект, который есть
Что такое мощность A/B-теста, как она связана с размером выборки и MDE, как посчитать нужное число участников и почему «незначимо» на слабом тесте ничего не доказывает.