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

Проверь себя · 1/3разбор после ответа
Колонка created_at имеет тип timestamp. Какой тип данных вернёт DATE_TRUNC('day', created_at)?

Зачем Uplift

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

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

Абсолютный и относительный uplift

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

Пример: CR контрольной группы 2%, тестовой 3%.

  • Абсолютный: +1 п.п.
  • Относительный: +50%

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

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

Данные: 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 контрольной и тестовой групп не пересекаются — uplift статистически значим (грубое приближение вместо z-test).

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

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

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

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

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

Ошибка 5. Несколько метрик. Считаете uplift по CR, AOV и выручке сразу. Множественные сравнения → ложные срабатывания. Используйте поправку Bonferroni или sequential testing.

Ошибка 6. Отрицательный uplift. Тестовая группа работает хуже контрольной — это валидный результат, его нельзя игнорировать.

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

FAQ

Абсолютный или относительный?

Абсолютный uplift показывают, когда база известна и важна сама величина в пунктах. Относительный берут, чтобы подчеркнуть масштаб роста, но на низких базах он обманчив.

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

Для конверсионных метрик относительный uplift +5–10% — это нормальный результат. Всё, что выше +20%, считается большим и нередко оказывается шумом.

Отрицательный uplift — что делать?

Не выкатывать тестовую версию в прод и разобраться, почему она проиграла контрольной. Отрицательный результат — это тоже полезный вывод.

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

Да. Если реальный эффект меньше заложенного MDE, uplift утонет в шуме, и тест не сможет надёжно его поймать.

Можно ли считать uplift в SQL для долгосрочных эффектов?

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