Чем меньше дисперсия метрики, тем меньше пользователей нужно, чтобы заметить тот же эффект. Размер выборки пропорционален дисперсии: снизили её вдвое, тест можно вести примерно вдвое короче. Поэтому снижение дисперсии одна из любимых тем senior-собеса.
Идея CUPED
CUPED (Controlled-experiment Using Pre-Experiment Data, Microsoft, 2013) использует данные о пользователе до теста. Выручка пользователя в тесте сильно связана с его выручкой за прошлый месяц. Часть разброса метрики объясняется тем, кто этот человек, а не тестом. Эту часть можно вычесть.
Пусть Y метрика в тесте, X та же метрика до теста (ковариата). Скорректированная метрика:
Y_cuped = Y - θ · (X - mean(X))
θ = cov(X, Y) / var(X)
- Среднее не меняется:
mean(X - mean(X)) = 0, поэтому разница средних между группами остаётся несмещённой оценкой эффекта. - Дисперсия падает в
(1 - ρ²)раз, где ρ корреляция X и Y. При ρ = 0.7 дисперсия уменьшится примерно вдвое. - θ считают по объединённым данным обеих групп (или одинаково для обеих), иначе можно внести смещение.
import statistics as st
def cuped(x, y):
theta = st.covariance(x, y) / st.variance(x)
mx = st.fmean(x)
return [yi - theta * (xi - mx) for xi, yi in zip(x, y)]
Требования к ковариате
- Не зависит от теста. Берут данные строго до начала эксперимента. Если взять метрику за период теста, она сама могла измениться от воздействия, и оценка эффекта сместится.
- Сильно коррелирует с метрикой. Чаще всего это та же метрика за прошлый период.
- Новые пользователи без истории: ковариату заполняют нулём или средним и добавляют признак «новый», эффект просто будет слабее.
Обобщение CUPED: регрессия метрики на несколько предтестовых признаков (CUPAC использует прогноз ML-модели как ковариату). Важно то же правило: признаки не должны зависеть от воздействия.
Стратификация
Если метрика сильно различается по сегментам (платформа, страна, новые и старые), можно:
- стратифицированно рандомизировать: внутри каждого сегмента делить 50/50, тогда доли сегментов в группах совпадут точно;
- постстратификация: посчитать среднее в каждом сегменте и сложить с весами сегментов во всей выборке. Это убирает часть дисперсии, связанной со случайным перекосом сегментов.
Ratio-метрики и дельта-метод
CTR, средний чек, клики на сессию: это R = Σx / Σy по пользователям (клики и показы каждого пользователя). Наблюдения внутри пользователя зависимы, поэтому считать дисперсию «по показам», как будто каждый показ независим, нельзя: она будет занижена.
Дельта-метод даёт приближённую дисперсию отношения средних через дисперсии и ковариацию пользовательских сумм:
Var(R) ≈ (1/n) · ( var(x)/μy² - 2·μx·cov(x,y)/μy³ + μx²·var(y)/μy⁴ )
где μx, μy средние по пользователям, n число пользователей в группе.
Линеаризация
Альтернатива дельта-методу: превратить ratio-метрику в обычную пользовательскую:
L_i = x_i - R_A · y_i
где R_A значение отношения в контрольной группе. Затем обычный t-тест по L_i. Знак эффекта совпадает с ratio-метрикой, а к L можно применять CUPED. Это удобно в платформах экспериментов: все метрики становятся пользовательскими.
Другие приёмы
- Винзоризация выбросов (обрезка по 99-му или 99.9-му перцентилю) резко снижает дисперсию денежных метрик. Порог фиксируют до теста.
- Triggered-анализ: анализировать только тех, кто дошёл до места изменения, одинаково в обеих группах. Пользователи, не видевшие изменения, добавляют только шум.
- Более чувствительная метрика: бинарная «сделал покупку» обычно шумит меньше выручки.
Частые ошибки
- Ковариата посчитана за период теста.
- θ подобрано отдельно в каждой группе.
- Дисперсия CTR посчитана по показам.
- Винзоризация с порогом, выбранным после взгляда на результат.
Что спросят на собесе
- Как работает CUPED и почему он не смещает оценку эффекта?
- Насколько CUPED снизит дисперсию при корреляции 0.6?
- Что можно и что нельзя использовать как ковариату?
- Как посчитать дисперсию CTR в A/B-тесте?
- Что такое линеаризация ratio-метрик?