Как посчитать delta method в SQL
Содержание:
Зачем delta method
Ratio-метрики (CTR = clicks/views, AOV = revenue/orders, sessions per user) — головная боль A/B. Стандартный t-test ломается: знаменатель тоже случайный, ему нельзя считать дисперсию как «сумма поделить на n». Delta method (он же linearization) даёт правильную формулу для variance ratio-метрики.
Идея линеаризации
Метрика R = X/Y. Если разложить вокруг среднего:
R ≈ μ_X/μ_Y + (1/μ_Y) × (X − μ_X) − (μ_X/μ_Y²) × (Y − μ_Y)Это «линеаризованный» ratio: каждое наблюдение i даёт single число r_i. После этого работаете с r_i как с обычной метрикой (Welch's t-test и т.д.).
Формула для ratio
Для каждого user_id с числителем x_i и знаменателем y_i:
r_i_linearized = (x_i − μ_X × y_i / μ_Y) / μ_YДисперсия R̂ = VAR(r_i_linearized) / n.
Delta method в SQL
CTR в A/B-тесте: numerator = clicks, denominator = views. По user_id:
WITH per_user AS (
SELECT
user_id,
variant,
SUM(CASE WHEN event = 'click' THEN 1 ELSE 0 END) AS clicks,
SUM(CASE WHEN event = 'view' THEN 1 ELSE 0 END) AS views
FROM ab_events
WHERE experiment_id = 'feed_v3'
GROUP BY user_id, variant
),
group_means AS (
SELECT
variant,
AVG(clicks) AS mean_x,
AVG(views) AS mean_y,
COUNT(*) AS n
FROM per_user
GROUP BY variant
),
linearized AS (
SELECT
u.variant,
(u.clicks - gm.mean_x * u.views / NULLIF(gm.mean_y, 0))
/ NULLIF(gm.mean_y, 0) AS r_i
FROM per_user u
JOIN group_means gm USING (variant)
)
SELECT
variant,
gm.mean_x / NULLIF(gm.mean_y, 0) AS ratio_point_estimate,
VAR_SAMP(l.r_i) / NULLIF(gm.n, 0) AS variance_of_ratio,
SQRT(VAR_SAMP(l.r_i) / NULLIF(gm.n, 0)) AS se_of_ratio
FROM linearized l
JOIN group_means gm USING (variant)
GROUP BY variant, gm.mean_x, gm.mean_y, gm.n;CI и t-statistic
Для разницы ratio между A и B используют стандартный Welch на r_i:
WITH a_stats AS (
SELECT
AVG(r_i) AS mean_r,
VAR_SAMP(r_i) AS var_r,
COUNT(*) AS n
FROM linearized
WHERE variant = 'A'
),
b_stats AS (
SELECT
AVG(r_i) AS mean_r,
VAR_SAMP(r_i) AS var_r,
COUNT(*) AS n
FROM linearized
WHERE variant = 'B'
)
SELECT
b.mean_r - a.mean_r AS diff_ratio,
(b.mean_r - a.mean_r)
/ NULLIF(SQRT(a.var_r / a.n + b.var_r / b.n), 0) AS t_statistic
FROM a_stats a, b_stats b;r_i имеет mean = 0 в каждой группе (центрирован вокруг group mean), но diff между mean_r двух групп — это разница ratio. Можно работать без префикса «mean — общий ratio группы».
Частые ошибки
Ошибка 1. Считать CTR = SUM(clicks) / SUM(views) без дисперсии.
Точечная оценка верна, но без variance тест невалиден. Delta method решает.
Ошибка 2. Считать AVG(clicks_per_view).
Это другая метрика — micro-average по строкам. Сильно искажается, если у части юзеров нет views.
Ошибка 3. Линеаризация на event-level вместо user-level. Если знаменатель variates по юзерам — линеаризуем на уровне рандомизации (обычно user). Не на уровне session, если бакетируете по user.
Ошибка 4. Не учитывать что μ_Y оценивается из тех же данных.
В строгой теории μ_X, μ_Y фиксированы. Использование выборочных средних — стандартная аппроксимация, но даёт оценку чуть смещённой при маленьких n.
Ошибка 5. Использовать μ_Y = 0.
Деление на 0. Если у юзера нет views — он не имеет смысла для CTR, либо исключайте, либо корректируйте определение.
Связанные темы
- Как посчитать t-test в SQL
- Как посчитать CUPED в SQL
- Как посчитать CTR в SQL
- Как посчитать AOV в SQL
FAQ
Когда нужен delta method?
Метрика-отношение, рандомизация выше уровня события (CTR при per-user, ARPV при per-user, conversion per session при per-user).
Альтернатива?
Bootstrap: тоже даёт CI без формул, но дороже компьют.
Что если знаменатель = 0?
Исключают юзера или меняют определение (например, CTR определён только для тех, кто видел хотя бы 1 раз).
Delta method для трёх ratio?
Усложняется, но та же логика — линеаризация через градиент.
Совместим с CUPED?
Да: сначала линеаризуете, потом применяете CUPED к r_i как к обычной метрике.