Привет, Хабр!
Каждому аналитику знакомо: при анализе A/B‑тестов важно выжимать максимум информации из данных. Но высокая дисперсия шума часто заставляет нас наращивать выборку и затягивать эксперименты. Как ускорить получение результата и повысить чувствительность теста? Один из способов — сократить разброс метрики без изменения ее среднего. Классическая формула размера выборки показывает, что количество данных N прямо пропорционально дисперсии σ². Получается, уменьшая σ², мы автоматически уменьшаем нужный объем данных или можем детектировать меньший эффект при тех же N.
Поэтому методы снижения дисперсии в A/B‑тестах становятся очень востребованными. В индустрии известны разные приемы: стратификация, бутстреп, сложные байесовские тесты, и, конечно же, ковариатный подход (CUPED/CUPAC и т. д.). Мы остановимся на одном из самых простых и эффективных приемов — CUPED (Controlled‑experiment Using Pre‑Experiment Data). Его суть проста и понятна: перед экспериментом у каждого пользователя была определенная метрика (скажем, прошлые покупки), и мы можем использовать эту информацию, чтобы скорректировать итоговую метрику и снизить шум.
Идея CUPED формулируется через новую скорректированную метрику:
где — исходная метрика эксперимента (например, выручка в тесте), а
— ковариата, измеренная до эксперимента и коррелирующая с
, но не зависящая от распределения пользователей на контроль/тест. Параметр
обычно берут равным
— это оптимальный выбор, минимизирующий дисперсию разности. По сути
он равен коэффициенту регрессии YYY на XXX. Фактически мы вычитаем из результата ту часть, которую можно предсказать по предэкспериментальным данным. Как отмечено в Glovo Tech Blog, при любом разность средних для скорректированной метрики будет несмещенной, а минимум дисперсии достигается именно при
.
Ковариата не должна зависеть от назначения варианта. Обычно берут именно данные до эксперимента, чтобы гарантировать независимость. Ковариаты — это показатели, измеренные до вмешательства и не зависящие от treatment. Часто просто используют ту же метрику, что и в эксперименте, посчитанную за прошлый период. Тогда при корректном применении средний эффект останется несмещенным, а дисперсия метрики существенно уменьшится.
Давайте посмотрим, как это воплотить на практике через SQL. Допустим, у нас есть две таблицы: во‑первых, user_activity
с историей активности пользователей, где мы можем вычислить метрику до эксперимента (кавариату), и во‑вторых, та же таблица (или другая) с метриками во время эксперимента. Например, хотим сравнить суммарную выручку пользователя за период эксперимента и использовать выручку в прошлом месяце как . В PostgreSQL можно написать следующий запрос, который агрегирует данные:
WITH pre AS (
SELECT user_id,
SUM(metric) AS metric_before
FROM user_activity
WHERE event_date BETWEEN '2024-12-01' AND '2024-12-31'
GROUP BY user_id
), exp AS (
SELECT user_id,
variation,
SUM(metric) AS metric_during
FROM user_activity
WHERE event_date BETWEEN '2025-01-01' AND '2025-01-07'
GROUP BY user_id, variation
)
SELECT e.variation,
COUNT(*) AS users_count,
AVG(e.metric_during) AS avg_after,
AVG(p.metric_before) AS avg_before
FROM exp e
LEFT JOIN pre p ON e.user_id = p.user_id
GROUP BY e.variation;
Запрос объединяет данные до (pre
) и во время (exp
) эксперимента по каждому пользователю. В результате мы получаем по каждой вариации (контроль/тест): число пользователей, среднее после и среднее до. По сути это основа — теперь можем переходить к расчету CUPED.
Дальше считаем параметры для коррекции: для каждой группы вычисляем средние, ст. отклонения и корреляцию между и
. Затем корректируем среднее следующим образом:
WITH data AS (
SELECT e.variation,
e.metric_during AS y,
p.metric_before AS x
FROM exp e
LEFT JOIN pre p ON e.user_id = p.user_id
),
stats AS (
SELECT variation,
COUNT(*) AS n,
AVG(y) AS ybar,
AVG(x) AS xbar,
STDDEV_SAMP(y) AS s_y,
STDDEV_SAMP(x) AS s_x,
CORR(x, y) AS r
FROM data
GROUP BY variation
)
SELECT
variation,
ybar AS original_mean,
ybar - (r * s_y / s_x) * (xbar - (SELECT AVG(xbar) FROM stats)) AS cuped_mean
FROM stats;
В этом примере в CTE stats
считаем нужные агрегаты: ybar
, xbar
, стандартные отклонения и корреляцию. Затем для каждой вариации (arm
) вычисляем скорректированное среднее: по формуле из ANCOVA мы отнимаем (r s_y / s_x) (xbar - xbar_all)
, где xbar_all
— среднее ковариаты по всем участникам. Результат — две группы со скорректированными средними. Мы видим, что благодаря учету предэкспериментальной метрики разброс снижается, а ожидаемая разность между средними (эффект) остается тем же.
Еще один вариант — сразу посчитать θ и применить его к каждому пользователю. Например:
WITH params AS (
SELECT
COVAR_POP(e.metric_during, p.metric_before) / VAR_POP(p.metric_before) AS theta
FROM exp e
JOIN pre p ON e.user_id = p.user_id
)
SELECT
e.variation,
AVG(e.metric_during - params.theta * p.metric_before) AS adjusted_avg
FROM exp e
JOIN pre p ON e.user_id = p.user_id
CROSS JOIN params
GROUP BY e.variation;
Здесь сначала вычисляем общий theta
как ковариацию деленную на дисперсию ковариаты. Затем для каждой вариации усредняем Y - theta * X
. По сути это то же самое: получаем скорректированные средние по группам.
Однако важно не забывать: ковариата должна быть действительно независима от treatment. Если вместо предэкспериментальной метрики взять что‑то, что меняется в ходе теста (или выбрать плохую ковариату), мы получим смещенный результат. LaunchDarkly особо подчёркивает: ковариаты — это то, что измерено до вмешательства. Если нарушение этого условия, то «эффект коврика» (как шуточно говорят) может превратить шум в ложный эффект.
В завершение: мы убедились, что легко можно повысить чувствительность теста, написав пару SQL‑запросов. Собирать предэкспериментальные метрики, рассчитывать θ и корректировать итоговую метрику — всё это укладывается в пару CTE. Такой приём доступен в любом SQL‑движке и уже применяется в аналитических платформах. Главное — следить за корректностью данных. Ковариата должна быть адекватной и независимой от назначения групп. Тогда ваши A/B‑эксперименты зашевелятся: эффекты начнут обнаруживаться быстрее и надёжнее. Удачи и удачных тестов!
Если вам близка тема экспериментов и анализа данных, обратите внимание на курс «Аналитик данных». На нем рассмотрите ключевые методы и инструменты работы с данными, включая подходы к проведению A/B‑тестов и уменьшению дисперсии метрик.
Готовы ли вы к серьезному обучению? Пройдите вступительный тест.
А если вы хотите подробнее изучить направления, связанные с аналитикой и анализом данных, рекомендуем ознакомиться с каталогом курсов, где представлены разные программы по аналитике — от базовых до продвинутых.