A/B-тесты на SQL с уменьшением дисперсии

от автора

Привет, Хабр!

Каждому аналитику знакомо: при анализе A/B‑тестов важно выжимать максимум информации из данных. Но высокая дисперсия шума часто заставляет нас наращивать выборку и затягивать эксперименты. Как ускорить получение результата и повысить чувствительность теста? Один из способов — сократить разброс метрики без изменения ее среднего. Классическая формула размера выборки показывает, что количество данных N прямо пропорционально дисперсии σ². Получается, уменьшая σ², мы автоматически уменьшаем нужный объем данных или можем детектировать меньший эффект при тех же N.

Поэтому методы снижения дисперсии в A/B‑тестах становятся очень востребованными. В индустрии известны разные приемы: стратификация, бутстреп, сложные байесовские тесты, и, конечно же, ковариатный подход (CUPED/CUPAC и т. д.). Мы остановимся на одном из самых простых и эффективных приемов — CUPED (Controlled‑experiment Using Pre‑Experiment Data). Его суть проста и понятна: перед экспериментом у каждого пользователя была определенная метрика (скажем, прошлые покупки), и мы можем использовать эту информацию, чтобы скорректировать итоговую метрику и снизить шум.

Идея CUPED формулируется через новую скорректированную метрику:

Ycuped=Y−θ X,

где Y — исходная метрика эксперимента (например, выручка в тесте), а X — ковариата, измеренная до эксперимента и коррелирующая с Y, но не зависящая от распределения пользователей на контроль/тест. Параметр θ обычно берут равным

\theta = \frac{\mathrm{cov}(Y,X)}{\mathrm{Var}(X)}​ — это оптимальный выбор, минимизирующий дисперсию разности. По сути

он равен коэффициенту регрессии YYY на XXX. Фактически мы вычитаем из результата ту часть, которую можно предсказать по предэкспериментальным данным. Как отмечено в Glovo Tech Blog, при любом θ разность средних для скорректированной метрики будет несмещенной, а минимум дисперсии достигается именно при \theta = \mathrm{cov}(Y,X)/\mathrm{Var}(X).

Ковариата X не должна зависеть от назначения варианта. Обычно берут именно данные до эксперимента, чтобы гарантировать независимость. Ковариаты — это показатели, измеренные до вмешательства и не зависящие от treatment. Часто просто используют ту же метрику, что и в эксперименте, посчитанную за прошлый период. Тогда при корректном применении средний эффект останется несмещенным, а дисперсия метрики существенно уменьшится.

Давайте посмотрим, как это воплотить на практике через SQL. Допустим, у нас есть две таблицы: во‑первых, user_activity с историей активности пользователей, где мы можем вычислить метрику до эксперимента (кавариату), и во‑вторых, та же таблица (или другая) с метриками во время эксперимента. Например, хотим сравнить суммарную выручку пользователя за период эксперимента и использовать выручку в прошлом месяце как X. В 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.

Дальше считаем параметры для коррекции: для каждой группы вычисляем средние, ст. отклонения и корреляцию между Y и X. Затем корректируем среднее следующим образом:

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‑тестов и уменьшению дисперсии метрик.

Готовы ли вы к серьезному обучению? Пройдите вступительный тест.

А если вы хотите подробнее изучить направления, связанные с аналитикой и анализом данных, рекомендуем ознакомиться с каталогом курсов, где представлены разные программы по аналитике — от базовых до продвинутых.


ссылка на оригинал статьи https://habr.com/ru/articles/945834/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *