ibiza
CPM · CTR …
/

A/B-тесты в рекламе: деление трафика, SRM и подглядывание

≈ 8 мин чтения · обновлено

Чтобы A/B-тест в рекламе не объявил победителем случайность, мало поделить трафик на контроль и тест и сравнить CTR. Нужны еще четыре вещи: деление по пользователю, а не по запросу, если эффект переносится между показами; дисперсия CTR по дельта-методу; проверка долей групп (SRM) по назначению, а не по показам; решение по always-valid p, а не по обычному p-value.

Единица рандомизации: пользователь или запрос

Первое решение — что именно делится между группами.

Деление по запросу Деление по пользователю
Что получает группу Каждый запрос отдельно Человек целиком, во всех запросах
Один человек видит Обе версии вперемешку Только свою версию
Нужен стабильный ID Нет Да
Метрики Простые доли, тест долей Отношения по пользователям, дельта-метод
Подходит для Технических правок без «памяти»: формат ответа, верстка Ставок, креативов, частоты показов — всего, что влияет на поведение человека

Если тест меняет креатив или ставку, деление по запросу «загрязняет» группы. Человек видел оба креатива, кликнул на втором показе после первого — и неясно, какой группе засчитать клик. Деление по пользователю требует надежного ID, и тут важен identity-граф: если один человек приходит под двумя ID, он может попасть в обе группы.

Запросы без идентификатора при делении по пользователю не участвуют в тесте. Нельзя подставлять вместо пользователя ID запроса: тогда один и тот же человек сегодня без ID, завтра с ним окажется в обеих группах.

Детерминированное назначение по хешу

Хранить таблицу «пользователь → группа» не нужно. Группу вычисляют хешем:

корзина = hash(соль + ":" + user_id) mod 10000

Корзины от 0 до 9999 делятся по накопленным весам групп. Например, при весах 50/50: корзины 0–4999 — контроль, 5000–9999 — тест.

Пример (иллюстративный). Для пользователя ibz_7f3a… и соли 9c41e0d2a7b85f13 хеш дает корзину 3127. Это контроль, и в любом запросе, на любом сервере, в любой день результат будет тем же.

Свойства такой схемы:

  • Стабильность. Тот же пользователь при той же соли всегда в той же группе, без обращений к базе.
  • Независимость экспериментов. У каждого теста своя случайная соль. Попадание в тестовую группу одного эксперимента не повышает шанс попасть в тестовую группу следующего.
  • Хрупкость весов. Смена 50/50 на 30/70 сдвигает границу с 5000 на 3000: пользователи из корзин 3000–4999 переезжают из контроля в тест. Поэтому у запущенного теста веса, соль и единица рандомизации не меняются. Новое распределение — это новый эксперимент.
  • Хеш с хорошим перемешиванием. У некоторых простых хешей (например, FNV-1a) младшие биты результата зависят только от младших бит входа, а остаток от деления на 10 000 это «видит». Нужен хеш с лавинным эффектом во всех битах.

Еще одно правило: один объект (например, кампания) — один эксперимент одновременно. Если показ попадает сразу в два теста, его нельзя честно приписать ни одному.

Метрики-отношения и дельта-метод

CTR — это отношение: клики к показам. При делении по пользователю наблюдения внутри группы не независимы: один активный пользователь дает много показов и кликов, и его поведение коррелировано. Обычная биномиальная формула p(1−p)/N в этом случае занижает дисперсию, и тест долей объявляет значимыми случайные различия.

Правильная дисперсия отношения R = ΣY / ΣX (Y — клики пользователя, X — его показы) считается по пользователям дельта-методом:

Var(R) ≈ ( s²_Y − 2R·s_XY + R²·s²_X ) / ( n · μ_X² )

Здесь n — число пользователей, s² и s_XY — выборочные дисперсии и ковариация по пользователям, μ_X — средние показы на пользователя.

Отношение этой дисперсии к биномиальной называют эффектом дизайна (design effect).

Пример (иллюстративный). Биномиальная стандартная ошибка CTR в группе — 0,010 п.п., по дельта-методу — 0,016 п.п. Эффект дизайна — (0,016 / 0,010)² ≈ 2,6. Значит, нужно примерно в 2,6 раза больше показов, чем дает наивный расчет, а различие, которое выглядело значимым при z = 2,5, на деле дает z ≈ 1,6.

При делении по запросу каждый запрос — независимое испытание, и обычный z-тест двух долей корректен.

SRM: когда группы набраны не по плану

Sample ratio mismatch (SRM) — расхождение фактических долей групп с заданными весами. Проверка — критерий χ² согласия:

χ² = Σ (наблюдено_i − ожидалось_i)² / ожидалось_i,   степеней свободы = групп − 1

Пример (иллюстративный). Веса 50/50, в тест попало 100 000 пользователей: 50 900 в контроль, 49 100 в тест. χ² = 900²/50 000 · 2 = 32,4, p ≈ 1,3·10⁻⁸. Перекос всего 0,9 п.п., но случайно он почти невозможен: назначение или учет сломаны.

Порог для флага SRM обычно берут строгим, p < 0,001, иначе он будет срабатывать случайно в каждом двадцатом тесте. Если флаг поднят, сравнивать метрики нельзя, сначала нужно найти поломку.

Почему SRM считают по назначению, а не по показам

Самая частая ошибка — считать доли групп по показам. Если тест меняет ставку, тестовая группа законно выигрывает больше или меньше аукционов. Это эффект, а не поломка.

Пример (иллюстративный). Тест повышает ставку на запросах с высоким прогнозом клика. Назначение — ровно 50/50 по пользователям, пришедшим в запросах. Но тестовая группа выигрывает чаще, и показы делятся 55/45. Проверка по показам кричит «SRM!», хотя разбиение исправно. Проверка по уникальным пользователям во входящих запросах, с группой, вычисленной той же формулой хеша, показывает честные 50/50.

Вторая полезная проверка: группа, записанная в событиях, должна совпадать с группой, которую дает формула от соли и ID. Расхождение значит, что сервер назначает не то или учет пишет не то.

Подглядывание и always-valid p-value

Классический p-value рассчитан на одну проверку в конце теста заранее заданного объема. Если смотреть на него каждый день и остановиться при первом p < 0,05, вероятность ложной победы растет с каждым взглядом. Классический расчет Армитиджа, Макферсона и Роу (Armitage, McPherson, Rowe, 1969) для нормально распределенной метрики дает при пяти равномерных проверках около 14%, при десяти — около 19%, при двадцати — около 25% вместо заявленных 5%. При неравномерных проверках, например частых в начале теста, инфляция может быть еще больше.

Решение — последовательные тесты. Один из самых практичных — mSPRT (mixture sequential probability ratio test), на котором построен always-valid p-value:

Λ = √( V / (V + τ²) ) · exp( τ²·θ̂² / (2V·(V + τ²)) ),     p = min(1, 1/Λ)

Здесь θ̂ — наблюдаемая разность метрики между группами, V — дисперсия этой разности, τ² — масштаб ожидаемого эффекта (разумно брать порядка квадрата MDE в абсолютных единицах). Такой p можно смотреть сколько угодно раз: вероятность хоть однажды увидеть p < α при отсутствии эффекта не превышает α.

Пример (иллюстративный). CTR контроля 0,50%, теста 0,55%, стандартная ошибка разности 0,018 п.п. Классический p-value = 0,005, «значимо». Always-valid p при τ = 10% от контроля (0,05 п.п.) = 0,097, «пока нет». Цена возможности подглядывать — тест должен набрать больше данных, прежде чем признать эффект.

Мощность и MDE: сколько ждать

MDE (minimum detectable effect) — минимальный эффект, который тест надежно заметит. Его выбирают до запуска, исходя из того, какой эффект важен для бизнеса. Требуемый объем на группу для доли p при уровне значимости α и мощности 1−β:

n ≈ ( z_{1−α/2}·√(2p̄q̄) + z_{1−β}·√(p₁q₁ + p₂q₂) )² / (p₂ − p₁)²,    p₂ = p₁·(1 + MDE)
Базовый CTR Относительный MDE Показов на группу (α = 0,05, мощность 80%)
0,5% 5% ≈ 1 280 000
0,5% 10% ≈ 328 000
0,5% 20% ≈ 86 000
0,5% 30% ≈ 40 000

При делении по пользователю эти числа умножают на эффект дизайна. Вывод из таблицы: вдвое меньший эффект требует примерно вчетверо больше данных. Тест, которому не хватает объема, может только «случайно победить». Поэтому, пока объем не набран, решение принимают по always-valid p, а не по классическому.

Чек-лист перед запуском

  1. Единица рандомизации выбрана по природе изменения (пользователь или запрос).
  2. Задана ровно одна контрольная группа, веса в сумме дают 100%.
  3. MDE, α и мощность выбраны заранее, объем посчитан с учетом эффекта дизайна.
  4. Метрика определена однозначно: клики — только валидные, иначе выиграет группа, которая чаще попадает на мусорный инвентарь.
  5. Объект теста не участвует в другом эксперименте.
  6. SRM проверяется по назначению, решение принимается по always-valid p.

A/B-эксперименты в Ibiza

Эксперименты в Ibiza создаются в админке и делят трафик выбранных кампаний (весь трафик — только с явным флагом). Единица рандомизации — пользователь (внутренний профиль identity-графа) или запрос. Групп от 2 до 8, ровно одна контрольная, веса задаются в базисных пунктах и в сумме дают 100%. При создании генерируется случайная соль. Группа вычисляется DSP детерминированно, как XXH64 от строки «соль:ID» по модулю 10 000, без обращений к хранилищу. После запуска группы, соль, единица и фича заморожены, пауза сохраняет назначение, а одна кампания не может участвовать в двух экспериментах. Группа передается в ссылках трекинга и оседает в показах, кликах и конверсиях.

Сейчас эксперименты поддерживают три фичи: ставку по прогнозу CTR (множитель в коридоре), выбор креатива по прогнозу CTR и форму нативного ответа SSP. Отчет показывает по группам показы, валидные клики, конверсии, расход, CTR, CR, CPC и CPM. Сравнение с контролем при делении по пользователю идет дельта-методом, при делении по запросу — z-тестом двух долей. Решение о значимости принимается по always-valid p (mSPRT с масштабом эффекта τ = MDE × контроль). SRM считается по назначению: уникальные единицы во входящих запросах, группа вычисляется той же формулой хеша, что и в DSP. Отдельно проверяется, совпадает ли записанная группа с вычисленной. Отчет также оценивает необходимый объем с учетом эффекта дизайна и предупреждает, если тест еще недобран. Пошаговая настройка — в документации по A/B-тестам.

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

Что делать, если тест показал SRM?

Не делать выводов по метрикам. SRM означает, что группы набраны не по задуманным долям: сломано назначение или учет. Сначала найти и исправить причину, затем перезапустить тест с новой солью.

Можно ли остановить тест, как только p-value стало меньше 0,05?

Для классического p-value — нет: каждая промежуточная проверка увеличивает шанс ложной победы. Останавливать по ходу можно только по always-valid p-value (например, mSPRT), которое рассчитано на многократный просмотр.

Почему нельзя менять доли групп посреди теста?

При детерминированном назначении смена весов сдвигает границы групп, и часть пользователей переезжает из контроля в тест. Их история смешивает эффекты обеих групп. Правильный путь — остановить тест и запустить новый.