Как посчитать CUPED в SQL
Содержание:
Зачем CUPED
CUPED (Controlled-experiment Using Pre-Experiment Data) — техника снижения дисперсии в A/B-тесте за счёт исторической ковариаты. Реальный эффект: тот же MDE достигается на 20–50% меньшей выборке или быстрее по времени. Microsoft опубликовали в 2013, с тех пор стандарт в продуктовой A/B-аналитике.
Идея ковариаты
Если у пользователя была выручка до эксперимента (X), и текущая метрика — выручка в эксперименте (Y), они коррелируют. Корректируем Y:
Y_cuped = Y − θ × (X − mean(X))где θ = cov(X, Y) / var(X). Дисперсия Y_cuped меньше, чем у Y, на (1 − ρ²) × var(Y), где ρ — корреляция X и Y.
CUPED в SQL
WITH base AS (
SELECT
u.user_id,
u.variant,
u.revenue_pre AS x, -- ковариата: revenue за 30 дней ДО эксперимента
COALESCE(SUM(o.amount), 0) AS y -- метрика: revenue в эксперименте
FROM ab_users u
LEFT JOIN orders o
ON o.user_id = u.user_id
AND o.created_at >= u.bucket_at
WHERE u.experiment_id = 'paywall_v3'
GROUP BY u.user_id, u.variant, u.revenue_pre
),
theta_calc AS (
SELECT
COVAR_POP(y, x) / NULLIF(VAR_POP(x), 0) AS theta,
AVG(x) AS mean_x
FROM base
),
adjusted AS (
SELECT
b.variant,
b.y,
b.y - t.theta * (b.x - t.mean_x) AS y_cuped
FROM base b
CROSS JOIN theta_calc t
)
SELECT
variant,
AVG(y) AS mean_y_raw,
AVG(y_cuped) AS mean_y_cuped,
VAR_SAMP(y) AS var_y_raw,
VAR_SAMP(y_cuped) AS var_y_cuped,
1 - VAR_SAMP(y_cuped) / NULLIF(VAR_SAMP(y), 0) AS variance_reduction
FROM adjusted
GROUP BY variant;Среднее остаётся прежним (ковариата центрирована), а дисперсия падает.
Скорректированный t-test
После CUPED считаем стандартный Welch's t-test на y_cuped вместо y:
WITH cuped_stats AS (
SELECT
variant,
COUNT(*) AS n,
AVG(y_cuped) AS mean,
VAR_SAMP(y_cuped) AS variance
FROM adjusted
GROUP BY variant
),
pair AS (
SELECT
MAX(CASE WHEN variant = 'A' THEN n END) AS n_a,
MAX(CASE WHEN variant = 'A' THEN mean END) AS mean_a,
MAX(CASE WHEN variant = 'A' THEN variance END) AS var_a,
MAX(CASE WHEN variant = 'B' THEN n END) AS n_b,
MAX(CASE WHEN variant = 'B' THEN mean END) AS mean_b,
MAX(CASE WHEN variant = 'B' THEN variance END) AS var_b
FROM cuped_stats
)
SELECT
mean_b - mean_a AS diff_cuped,
(mean_b - mean_a) / SQRT(var_a / n_a + var_b / n_b) AS t_statistic_cuped
FROM pair;Та же логика, что в t-test, но дисперсии после CUPED ниже → t-stat больше → быстрее достигается значимость.
Снижение дисперсии в процентах
SELECT
(1 - VAR_SAMP(y_cuped) / NULLIF(VAR_SAMP(y), 0)) * 100 AS variance_reduction_pct
FROM adjusted;Типичное значение для выручки в продукте — 20–40%, для конверсии почти 0 (бинарные метрики плохо снижаются ковариатой).
Частые ошибки
Ошибка 1. Ковариата из периода эксперимента.
Если X собран после bucket_at — это утечка данных, нарушение независимости. Берите ковариату строго из периода до эксперимента.
Ошибка 2. Считать theta в каждой группе отдельно. Theta должна оцениваться на объединённых данных (обе группы вместе), иначе оценка смещена.
Ошибка 3. CUPED на бинарных метриках. Для конверсии корреляция с покупками до эксперимента близка к 0 — снижение дисперсии почти не работает. CUPED имеет смысл для непрерывных метрик.
Ошибка 4. Новые пользователи без истории. Выручка до эксперимента = 0 для всех новичков → ковариата не помогает. Для когортных экспериментов CUPED иногда теряет силу.
Ошибка 5. Несколько ковариат сразу. Базовый CUPED — одна ковариата. Если хочется несколько — это уже OLS с регрессорами (CUPAC / линейная регрессия).
Связанные темы
- Как посчитать t-test в SQL
- Как посчитать sample size в SQL
- CUPED простыми словами
- CUPED: снижение дисперсии в A/B
FAQ
Какая ковариата подойдёт?
Та, что сильнее всего коррелирует с целевой метрикой. Для выручки берут выручку за доэкспериментальный период, для удержания — активность пользователя до эксперимента.
Снижение дисперсии на 20% — это много?
Да, это ощутимо: снижение дисперсии на 20% позволяет уменьшить размер выборки примерно на 36% при том же MDE. На практике это заметно ускоряет эксперимент.
CUPED меняет точечную оценку?
Нет, среднее остаётся прежним — CUPED не смещает точечную оценку. Падает только дисперсия, поэтому доверительный интервал становится уже.
Что вместо theta для нескольких ковариат?
Для нескольких ковариат используют линейную регрессию на доэкспериментальных признаках — этот подход называется CUPAC.
Можно ли в Postgres без расширений?
Да. Функции COVAR_POP и VAR_POP встроены в Postgres, поэтому никакие расширения или аддоны не нужны.