new-lvl.pro · Статьи · A/B
Статья // 12 мин чтения

A/A-тесты: зачем нужны
и что делать,
если падает значимость

Самый недооценённый тест в продуктовой аналитике. Заводят раз в год, узнают, что платформа сплита врёт, ratio-метрика течёт, а трекинг дублирует события. Разбираем, зачем запускать A/A, как читать «процент значимых», 5 причин ложной значимости и чек-лист отладки из 6 шагов.

Зачем вообще нужен A/A

A/A-тест — это эксперимент без воздействия. Берёшь юзеров, случайно делишь их на две группы, обе получают одну и ту же версию продукта, а потом считаешь метрику ровно так же, как считал бы её в A/B. Звучит бессмысленно — мы заранее знаем, что эффекта нет. Но в этом и смысл: если «эффект» появился — где-то баг, и пока его не нашёл, любому A/B-результату верить опасно.

Платформа экспериментов — это много слоёв: сплиттер, трекинг, хранилище логов, агрегация метрик, стат-процедура. Каждый слой может тихо ломаться. A/B такие поломки часто маскирует — реальный эффект перекрывает шум, и команда раскатывает фичу, не понимая, что половина «лифта» была артефактом трекинга. A/A ловит это до того, как оно стоит денег.

01 / Сплит
Корректность сплитования
Юзеры действительно делятся 50/50 без перекоса по платформе, гео, типу устройства, давности регистрации.
02 / Метрика
Корректность сборки метрик
Числитель, знаменатель и единица анализа считаются одинаково в обеих группах. Никаких дублей и пропусков.
03 / Статистика
Корректность стат-процедуры
P-value распределён равномерно, FPR на уровне α=0.05. Тест не консервативен и не анти-консервативен.

Без A/A эти три вещи проверить нечем. Можно полагаться на интуицию архитектора платформы, но интуиция не масштабируется на новые метрики и новые кейсы. A/A — это дешёвая формальная проверка, которая поднимает руку, когда что-то отъехало.

Откуда в A/A берётся «значимость»

Когда команда впервые запускает A/A и получает p < 0.05, реакция всегда одна: «как же так, мы ничего не меняли — а тест значим». Это не баг, это статистика. При уровне значимости α=0.05 ровно 5% A/A-тестов должны давать значимый результат — даже если платформа идеальна. Это и называется False Positive Rate.

Поэтому одного A/A недостаточно. Нужна симуляция: запускаем 1000 (а лучше 10000) A/A на исторических данных и смотрим, какой процент из них дал p < 0.05.

FPR = |{ pi < 0.05 }| / N, где N = 1000+
Процент симуляций A/A, в которых тест ложно показал значимое различие.

Дальше — простая логика. Идеальный FPR равен α (5%). В реальной выборке из 1000 симуляций будет случайное отклонение — норма примерно 4–6%. А вот выходы за эти границы — повод копать.

FPR в A/A Диагноз Что делать
4–6% Норма Платформа здорова. Можно запускать A/B.
7–10% Анти-консервативно Тест ложно срабатывает чаще нормы. Чинить: SRM, дубликаты, ratio.
2–3% Консервативно Дисперсия переоценена. Тест может пропускать реальные эффекты. Часто — delta-method применили там, где не надо, или ICC недооценили.
> 15% Серьёзный баг Сплитование, метрика или стат-процедура серьёзно сломаны. Останавливай все A/B до выяснения.
// Запомни одно правило
Если у тебя один A/A показал p < 0.05 — это нормально, такое бывает в 5% случаев. Если 7+ из 100 показали — это уже сигнал, копай. Один тест ничего не говорит, нужна симуляция.

Дополнительная проверка — равномерность распределения p-value. В правильно работающем A/A p-value должен быть распределён равномерно от 0 до 1. Гистограмма с перекосом к нулю — анти-консерватизм. Гистограмма с горбом в районе 0.5 — консерватизм. Это короче и нагляднее, чем считать только долю значимых.

Два типа A/A: офлайн и продакшн

A/A-тесты делятся на два формата, и они проверяют разные вещи. Перепутать — потерять время и не найти баг.

Офлайн A/A Продакшн A/A
Где запускается На исторических данных в Python/SQL В платформе экспериментов, реальный сплит юзеров
Сколько симуляций 1000–10000 (cheap) Обычно 1–2, реже до 10 (expensive)
Длительность Минуты 1–4 недели на тест
Что проверяет Метрика + стат-тест + единица анализа Сплитование + трекинг + кэши + всё сразу
Какие баги ловит Bias в метрике, неверный стат-тест, неучтённая корреляция SRM, дубликаты, региональные кэши, baking trafic
Когда использовать Перед каждой новой метрикой / новым стат-методом После изменений в системе сплитования или трекинге

Хорошая практика: офлайн A/A — обязательный, продакшн A/A — по событию. Офлайн делают каждый раз перед добавлением новой метрики или нового стат-теста (быстро, дёшево, можно автоматизировать в CI). Продакшн запускают после изменений в инфраструктуре экспериментов или при первом запуске на новой платформе.

Офлайн A/A: код

aa_offline.py
import numpy as np
import pandas as pd
from scipy import stats

def offline_aa(df: pd.DataFrame, metric: str, n_sim=1000):
    """
    Случайно разбивает юзеров на A и B, считает t-тест, повторяет.
    Возвращает массив p-value длиной n_sim.
    """
    p_values = []
    users = df.user_id.unique()
    for _ in range(n_sim):
        groups = np.random.choice(['A', 'B'], size=len(users))
        mapping = dict(zip(users, groups))
        df['group'] = df.user_id.map(mapping)
        a = df[df.group == 'A'][metric]
        b = df[df.group == 'B'][metric]
        _, p = stats.ttest_ind(a, b, equal_var=False)
        p_values.append(p)
    return np.array(p_values)

p = offline_aa(historical_df, metric='revenue', n_sim=1000)

# Доля значимых — должна быть около 0.05
print(f"FPR: {(p < 0.05).mean():.3f}")

# Распределение p-value — должно быть равномерным
import matplotlib.pyplot as plt
plt.hist(p, bins=20); plt.show()

Если FPR в диапазоне 4–6% и гистограмма равномерная — тест и метрика здоровы. Если нет — иди по чек-листу ниже.

Когда запускать A/A обязательно

A/A — не ежедневная процедура. Это контроль, который запускают после конкретных событий в инфраструктуре экспериментов. Пять основных триггеров:

01 / Сплит
Новая система сплитования
Переписали хешинг, поменяли соль, добавили мульти-вариантный режим. Гарантировано меняет распределение групп — проверять.
02 / Метрика
Новая метрика в каталоге
Особенно важно для производных и ratio: новый numerator, новый knock-out по событиям. Бывает, что считается на сессиях, а сплит — на юзерах.
03 / Ratio
Новая ratio-метрика
Конверсия, CTR, средний чек. Простой t-тест на ratio даёт неверную дисперсию — нужен delta-method или линеаризация. A/A покажет, применили ли правильно.
04 / Идентификация
Новая идентификация юзера
Переход с device-id на login-based, merge гостевых сессий с залогиненными. У одного юзера могут оказаться оба варианта — сплит ломается.
05 / Трекинг
Большой рефакторинг трекинга
Перенесли сборку событий с фронта на бэк, заменили SDK, новый клиент аналитики. Дублирующиеся события и потери — типичная плата за такие миграции.
06 / Запуск
Первый A/B на новой платформе
Если ты не команда, которая собрала платформу, считай, что она ещё не валидирована. Один продакшн A/A перед первым «настоящим» A/B окупается на годы вперёд.
// Цена пропуска
Без A/A можно крутить A/B-тесты на сломанной платформе годами. Команда верит результатам, продакт раскатывает фичи, а половина «значимости» — это перекошенный сплит или дубли в трекинге. Чем раньше поставлен A/A в процесс — тем дешевле починка.

5 причин ложной значимости в A/A

Если FPR в твоём A/A зашкаливает, виновата почти всегда одна из этих пяти штук. По частоте — от самых распространённых к более редким.

// причина 01
Sample Ratio Mismatch (SRM)
Сплит назначен 50/50, а фактически в группе A — 50.7%, в группе B — 49.3%. Хи-квадрат-тест на размер групп выдаёт p < 0.001. Это означает, что часть юзеров «утекла» — не попала в свою группу из-за поломки трекинга, бот-фильтра, race condition в назначении групп. Самая частая причина ложной значимости в продакшн A/A.
проверь scipy.stats.chisquare([n_a, n_b], [exp_a, exp_b]). Если SRM — иди в логи сплита, ищи юзеров, у которых group менялся, и место, где они отсеиваются.
// причина 02
Дублирующиеся события в трекинге
Один и тот же клик пишется в лог дважды (retry в SDK, ошибка дедупа на бэке, два аналитических снапшота). Это не обязательно одинаково по группам — иногда дубль появляется только в одной из них. Метрика «количество событий на юзера» неравномерно надувается, t-тест говорит «значимо».
посчитай events_per_user в обеих группах и распределение по дублям. Если в одной группе хвост толще — копай SDK или ETL. Часто помогает DISTINCT (user_id, event_id) перед агрегацией.
// причина 03
Не-iid юзеры: единица анализа ≠ единица рандомизации
Сплитуешь по юзерам, а считаешь конверсию по сессиям или заказам. У одного юзера много сессий — наблюдения коррелируют. Обычный t-тест считает дисперсию как для iid-выборки, и она получается заниженной — отсюда лишние ложные срабатывания. Проблема ровно та же в кросс-девайсе и в B2B-аккаунтах.
unit of analysis = unit of randomization. Аггрегируй до уровня юзера: sum(orders) per user_id, или применяй cluster-robust стандартные ошибки, или переходи к delta-method.
// причина 04
Кэш CDN: группы попадают на разные edge-серверы
Edge-кэш может агрессивно держать одну версию фронта или конфига. Если ключ кэширования игнорирует группу эксперимента — часть юзеров видит «не свою» версию, и сплит фактически перекошен. На уровне инфраструктуры всё в порядке, на уровне доставки — половина treatment получает control.
в кэш-ключе обязательно учитывай experiment_id и group. Запусти продакшн A/A на каждом региональном edge отдельно — если FPR разный по регионам, кэш — главный подозреваемый.
// причина 05
Ratio-метрика без delta-method
Считаешь конверсию как sum(orders) / sum(visits), потом применяешь t-тест к этой ratio по юзерам. Дисперсия ratio считается через дельта-метод (или линеаризацию), не как у нормальной метрики. Если применить простой t-тест — дисперсия занижена, FPR улетает выше 5%. Особенно сильно эффект на маленьких знаменателях.
для ratio — delta-method: дисперсия = (σ²X / Y² ) + ... − 2·X·Cov(X,Y) / Y³, или линеаризация по подходу Авито/Яндекса. В матрице стат-тестов есть конкретные формулы для типичных ratio.
// Ещё две причины, которые встречаются реже
Бот-фильтр в одной группе. Очень асимметричный фильтр (например, треш с одного гео ушёл только в B) — сразу SRM. Multiple testing без поправки. Если на одной выборке гоняешь A/A по 20 метрикам сразу — какая-нибудь да выстрелит. Применяй Holm или Bonferroni для семейства метрик.

Чек-лист отладки: 6 шагов

A/A показал высокий FPR — что дальше? Не паниковать, не отменять A/B вслепую. Пройти по шести шагам в правильном порядке: от самой частой и самой дешёвой проверки к самой редкой и дорогой.

6 шагов отладки A/A
1
SRM-чек. Хи-квадрат на размер групп: chisquare([n_a, n_b], [N/2, N/2]). Если p < 0.001 — это самая частая поломка. Останавливайся здесь, пока не починишь сплиттер. На SRM любые дальнейшие проверки бессмысленны.
2
Дубликаты и пропуски в логах. Посчитай events_per_user и распределение в обеих группах. Если хвосты разные — копай ETL и SDK. Применяй дедупликацию по (user_id, event_id, timestamp) и пересчитай A/A.
3
Unit of randomization vs unit of analysis. Если сплит по юзерам, а метрика — по сессиям/заказам/действиям — это твоя проблема. Аггрегируй до уровня юзера или применяй cluster-robust SE. Должно сразу подтянуть FPR ближе к 5%.
4
Стат-метод под метрику. Ratio (конверсия, CTR, средний чек) — delta-method или линеаризация, не t-тест в лоб. Бинарные метрики маленьких пропорций — Z-test пропорций или Fisher's exact на маленьких выборках. Не-нормальные распределения с тяжёлыми хвостами — bootstrap или Mann–Whitney.
5
CDN и региональные кэши. Запусти продакшн A/A отдельно по основным регионам. Если в одном регионе FPR резко выше — проблема в edge-кэше или в региональном CDN-конфиге. Добавь experiment_id и group в кэш-ключ.
6
Перезапуск. После каждой починки — повторно прогоняй офлайн A/A на исторических данных и продакшн A/A на свежем сплите. Не возвращайся к A/B, пока FPR не вернётся в зону 4–6% и гистограмма p-value не выглядит равномерной.
Собрать данные для A/A в SQL
Дедупликация событий, аггрегация до уровня юзера, расчёт ratio с числителем и знаменателем — это всё SQL-задачи. В тренажёре есть аналогичные форматы на маркетплейс-датасете.
Открыть тренажёр

A/A в кейс-интервью

A/A — стандартная тема на middle/senior-собесах в продуктовой аналитике. Спрашивают редко в лоб («что такое A/A»), чаще — в формате кейса: «у нас в A/B вышла странная картина, что бы ты сделал». Правильный ход — предложить A/A как первый шаг диагностики, а не сразу копать в продукт.

🎤 Что могут спросить
// Шаблон ответа на «что бы ты сделал»
(1) Перед любым A/B запустил бы офлайн A/A на этой метрике, проверил FPR и распределение p-value. (2) После раскатки экспериментальной платформы — продакшн A/A с SRM-чеком. (3) Если в A/A FPR > 6% — иду по чек-листу: SRM → дубликаты → unit of analysis → стат-метод → кэш. (4) К продукту лезу только после того, как платформа подтверждена. Этого хватает на 90% вопросов.

Частые вопросы

Что такое A/A-тест простыми словами?
A/A-тест — это эксперимент без воздействия: пользователи случайно делятся на две группы, обе получают одну и ту же версию продукта, метрика измеряется так же, как в A/B. Цель — проверить, что платформа экспериментов, метрики и стат-процедуры работают корректно. Если A/A показывает значимое различие чаще, чем в 5% случаев — где-то баг.
Какой процент значимых результатов в A/A считается нормой?
При α=0.05 ожидаемый процент — 5%. На практике норма 4–6%. Если 7–10% — есть систематическое смещение, чинить. Если меньше 3% — оценка дисперсии завышена, тесты слишком консервативны и могут пропускать реальные эффекты. Идеальная диагностика — не только доля значимых, но и форма гистограммы p-value: она должна быть равномерной от 0 до 1.
Чем офлайн A/A отличается от продакшн A/A?
Офлайн A/A — симуляция на исторических данных: случайно разбиваешь юзеров на A и B, считаешь метрику и стат-тест, повторяешь 1000+ раз. Быстро и дёшево, ловит баги в метрике и стат-процедуре. Продакшн A/A — реальный сплит в платформе экспериментов: обе ячейки получают control, тест крутится как обычный A/B. Медленнее, но ловит баги, которые невидимы на исторических данных (сплитование, трекинг, кэш).
Что такое Sample Ratio Mismatch (SRM)?
SRM — расхождение между ожидаемым и фактическим размером групп. Назначаешь сплит 50/50, а получаешь 50.7/49.3. Часто это статистически значимое отклонение (chi-square p < 0.001), и оно означает, что часть юзеров не попала в нужную группу. Причины: трекинг падает по-разному в группах, бот-фильтр перекошен, кэш CDN раздаёт разное, race condition в назначении групп. SRM → результаты A/B нельзя доверять, пока не починишь.
Что делать, если в A/A падает значимость?
По чек-листу из 6 шагов: (1) SRM — хи-квадрат на размер групп; (2) дубликаты — посчитать уникальных юзеров и события на юзера; (3) совпадение unit of randomization и unit of analysis — нельзя считать конверсию по сессиям, если сплитили по юзерам; (4) ratio-метрика — заменить t-тест на delta-method; (5) кэш CDN — проверить, что A/A покрывает все региональные edge-кэши; (6) перезапустить A/A и убедиться, что FPR вернулся к 5%.
Зачем запускать A/A, если у нас уже работает платформа экспериментов?
Запускают не для самоутверждения, а после изменений: новая система сплитования, новая ratio-метрика, переход на login-based идентификацию вместо device-id, большой рефакторинг трекинга. После любого такого события платформа может тихо начать врать. A/A — единственный недорогой способ это поймать, не подкладывая A/B под нерабочую инфраструктуру.
Сколько симуляций A/A нужно для надёжной оценки FPR?
Минимум 1000, лучше 10000. На 100 симуляциях стандартная ошибка доли значимых ≈ 2%, и ты не отличишь FPR=5% от FPR=7%. На 1000 — ошибка падает до 0.7%, разница уже видна. На 10000 — 0.2%, оценка надёжная. Если симуляции дорогие — начни с 1000 и наращивай, если результат на границе нормы.

Связанные материалы

Главное про A/A-тесты

A/A — это техосмотр платформы экспериментов. Не для красоты и не для отчёта, а чтобы поймать поломку до того, как она спрятала или придумала эффект в реальном A/B. Стоимость входа низкая: офлайн-симуляция — это 30 строк Python и 5 минут.

Запомни три ориентира: (1) при α=0.05 норма FPR — это 4–6%, а не «0%»; (2) офлайн A/A — обязательный, продакшн — после изменений в инфраструктуре; (3) если FPR уехал — почти всегда виноват один из пяти подозреваемых: SRM, дубликаты, не-iid юзеры, кэш CDN, ratio без delta-method.

Следующий шаг: возьми любую свою боевую метрику, прогони офлайн A/A на 1000 симуляций, посмотри на FPR и гистограмму p-value. Если впервые делаешь — почти гарантированно найдёшь баг. И сразу понятно, почему A/A — самое недооценённое упражнение в продуктовой аналитике.

АТ
Андрей Тарасенко
// Продуктовый аналитик · Авито · Ментор

A/A-тест — то, что менти не делают, пока я не настою. Делают — и три раза из пяти находят что-то: то ratio течёт, то сессии вперемешку с юзерами, то SRM. Любой A/B на сломанной платформе врёт уверенно — и тем больше денег стоит ошибка раскатки. Перед серьёзным экспериментом — всегда 5 минут на A/A.

Написать в Telegram
// ПРОВЕРЬ СЕБЯ

Разобрался? Проверь на квизе

15 ловушек A/B-тестов в формате квиза — peeking, SRM, ratio-метрики, novelty effect. А потом закрепи в SQL-тренажёре.

▶ Квиз: ловушки A/B ▶ SQL-тренажёр
Все материалы: База знаний · Telegram