Как посчитать Uplift в SQL

Закрепи формулу uplift в Карьернике
Запомнить надолго — 5 коротких сессий с задачами на эту тему. Бесплатно
Тренировать uplift в Telegram

Зачем Uplift

В A/B-тесте Treatment группа показала CR 5%, Control — 4%. Uplift = +1 п.п. (absolute) или +25% (relative). Какую цифру показывать команде? Зависит от контекста.

Uplift — основной способ выразить разницу в A/B. В статье — SQL и нюансы.

Absolute vs Relative Uplift

Absolute Uplift = CR_treatment - CR_control
Relative Uplift = (CR_treatment - CR_control) / CR_control × 100%

Пример: CR control 2%, treatment 3%.

  • Absolute: +1 п.п.
  • Relative: +50%

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

Базовый расчёт

Данные: ab_assignments(user_id, group_name, exp_id), events(user_id, event_type).

WITH stats AS (
    SELECT
        a.group_name,
        COUNT(DISTINCT a.user_id) AS users,
        COUNT(DISTINCT CASE WHEN e.event_type = 'purchase' THEN a.user_id END) AS conversions
    FROM ab_assignments a
    LEFT JOIN events e ON e.user_id = a.user_id
    WHERE a.exp_id = 'check_out_v2'
    GROUP BY a.group_name
)
SELECT
    group_name,
    users,
    conversions,
    conversions::NUMERIC / NULLIF(users, 0) * 100 AS cr_pct
FROM stats;

Затем для uplift:

WITH cr AS (
    SELECT
        group_name,
        COUNT(DISTINCT CASE WHEN e.event_type = 'purchase' THEN a.user_id END)::NUMERIC
            / NULLIF(COUNT(DISTINCT a.user_id), 0) AS cr
    FROM ab_assignments a
    LEFT JOIN events e ON e.user_id = a.user_id
    WHERE a.exp_id = 'check_out_v2'
    GROUP BY a.group_name
)
SELECT
    (SELECT cr FROM cr WHERE group_name = 'treatment') - (SELECT cr FROM cr WHERE group_name = 'control') AS absolute_uplift,
    ((SELECT cr FROM cr WHERE group_name = 'treatment') / NULLIF((SELECT cr FROM cr WHERE group_name = 'control'), 0) - 1) * 100 AS relative_uplift_pct;

Uplift по сегментам

WITH cr_seg AS (
    SELECT
        a.group_name,
        u.platform,
        COUNT(DISTINCT CASE WHEN e.event_type = 'purchase' THEN a.user_id END)::NUMERIC
            / NULLIF(COUNT(DISTINCT a.user_id), 0) AS cr
    FROM ab_assignments a
    JOIN users u ON u.user_id = a.user_id
    LEFT JOIN events e ON e.user_id = a.user_id
    WHERE a.exp_id = 'check_out_v2'
    GROUP BY a.group_name, u.platform
)
SELECT
    platform,
    MAX(CASE WHEN group_name = 'control' THEN cr END) AS cr_control,
    MAX(CASE WHEN group_name = 'treatment' THEN cr END) AS cr_treatment,
    MAX(CASE WHEN group_name = 'treatment' THEN cr END)
        - MAX(CASE WHEN group_name = 'control' THEN cr END) AS abs_uplift
FROM cr_seg
GROUP BY platform;
Закрепи формулу uplift в Карьернике
Запомнить надолго — 5 коротких сессий с задачами на эту тему. Бесплатно
Тренировать uplift в Telegram

Confidence interval

WITH stats AS (
    SELECT
        group_name,
        COUNT(DISTINCT a.user_id) AS n,
        COUNT(DISTINCT CASE WHEN e.event_type = 'purchase' THEN a.user_id END) AS k
    FROM ab_assignments a
    LEFT JOIN events e ON e.user_id = a.user_id
    WHERE a.exp_id = 'check_out_v2'
    GROUP BY a.group_name
)
SELECT
    group_name,
    n,
    k,
    k::NUMERIC / n AS p,
    1.96 * SQRT(k::NUMERIC / n * (1 - k::NUMERIC / n) / n) AS ci_radius
FROM stats;

95% CI для CR: p ± ci_radius. Если CI control и treatment не пересекаются — uplift статистически значим (грубый proxy для z-test).

Частые ошибки

Ошибка 1. Считать relative на низкой базе. CR 0,1% → 0,15% = +50% relative. Звучит огромно, но абсолютно — +0,05 п.п.

Ошибка 2. Считать без statistical significance. Uplift 2% при n=100 — может быть шумом. Нужен p-value / CI.

Ошибка 3. Игнорировать SRM. Перед uplift проверьте sample ratio — если control 48% / treatment 52% при 50/50 целевом, эксперимент сломан.

Ошибка 4. Кумулятивный vs final uplift. В A/B uplift первой недели может отличаться от финального. Не вытаскивайте preliminary results.

Ошибка 5. Несколько метрик. Считаете uplift по CR + AOV + revenue. Multiple comparisons → false positives. Используйте Bonferroni / sequential testing.

Ошибка 6. Negative uplift. Treatment работает хуже control — это валидный результат. Не игнорируйте.

Связанные темы

FAQ

Absolute или relative?

Absolute — если база известна. Relative — если хотите подчеркнуть рост (но на низких базах обманчиво).

Какой uplift считается большим?

В CR-метриках +5-10% relative — нормальный. +20%+ — большой, и часто шум.

Negative uplift — что делать?

Не катить treatment. Понять, почему хуже control.

Uplift зависит от MDE?

Да. Запустите A/B на меньшем эффекте, чем MDE, и он будет в шуме.

Можно ли uplift в SQL для long-term?

Стандартный — нет. Долгосрочные эффекты считаются через holdout.