← К портфолио Causal / Uplift — CUPED and Individual Treatment Effects preview
Стек
PythonLightGBMscikit-learnpandas / NumPymatplotlibpytestuv
Эффект
  • CUPED keeps the ATE (0.270 → 0.276) and cuts the standard error ~26%
  • Same power with ~5.6k users/arm instead of 10k (95% CI narrows 1.35x)
  • Uplift models recover that new users respond ~10x more than returning users
  • Implemented from scratch on LightGBM — no causalml/econml dependency
Исходники Смотреть на GitHub → Обновлено: Sep 18, 2026

Causal / Uplift — CUPED and Individual Treatment Effects

Контекст

Обычный двухвыборочный t-тест отвечает только на вопрос «работает ли эффект в среднем» и не использует пред-период. Из-за этого эксперименты просят больше трафика, чем нужно, а retention-акции уходят всем, хотя реагирует лишь часть аудитории.

Проект закрывает оба пробела двумя методами:

  • CUPED — снижение дисперсии по ковариате из пред-периода: тот же ATE, но уже CI, то есть меньше пользователей до нужной мощности.
  • Uplift-моделирование — оценка индивидуального эффекта (ITE): таргетировать акции на тех, кто реально реагирует, а не на всех.

Оба метода работают на синтетическом рандомизированном эксперименте с известным гетерогенным эффектом, поэтому оценки можно сверить с ground truth.

Данные и метод

Данные синтетические и детерминированные (seed = 42), 20 000 пользователей в рандомизированном эксперименте:

  • segmentnew (30%) / returning (70%) → гетерогенный эффект воздействия;
  • x_pre — ковариата пред-периода, коррелированная с исходом (ρ ≈ 0.67);
  • treatment — 50/50, независим от всего (чистая рандомизация);
  • tau_true — истинный индивидуальный эффект (только для оценки);
  • y_cont — непрерывный исход; y_bin — бинарная конверсия.

CUPED — та же оценка ATE, меньше дисперсия:

Метод ATE SE 95% CI
Naive 0.270 0.019 [0.232, 0.308]
CUPED 0.276 0.014 [0.247, 0.304]

Точечная оценка не меняется (0.270 → 0.276, в пределах шума). Стандартная ошибка сжимается на ~26% (×0.74), CI сужается в 1.35×. Снижение дисперсии ~45% фактически против 55% теоретически (разрыв — ковариата является прокси пред-периода, а не самим исходом).

Uplift — индивидуальный эффект, T- и S-learner:

Модель AUUC QINI uplift@20% corr(τ)
T-learner 0.0043 0.0014 0.072 0.50
S-learner 0.0057 0.0029 0.041 0.66
Random 0.0014 −0.0014 −0.015 0.007

Оговорка о честности: латентная ground-truth τ равна 0.60 (new) / 0.08 (returning), но конверсионный uplift ~0.11 / 0.01, потому что сигмоида при высокой базовой конверсии (~71%) дампит большие латентные эффекты. Сравнивать предсказанный бинарный uplift с латентной τ было бы несовпадением шкал; мы приводим ранговую корреляцию (без масштаба) и по-сегментное эмпирическое восстановление (одна шкала).

Запуск

uv run --with pandas --with numpy python data/generate_data.py
uv run --with pandas --with numpy --with scikit-learn --with lightgbm --with matplotlib python run.py
uv run --with pandas --with numpy --with scikit-learn --with lightgbm --with matplotlib --with pytest pytest -q

Результаты: reports/metrics.json + reports/uplift.png (QINI-кривые + сегментный uplift против ground truth).

Что нашли

CUPED даёт мощность бесплатно: новый дизайн эксперимента не нужен, нужен лишь лучший оценщик на уже собранных данных — при условии, что есть ковариата из пред-периода.

Uplift отвечает на другой вопрос, чем A/B-тест: не «работает ли воздействие в среднем», а «на ком оно работает». Методы дополняют друг друга, а не заменяют.

Модель восстановила форму эффекта: «новые» пользователи реагируют ~10× сильнее «возвращающихся» — тот самый сигнал, по которому действовала бы скидочная кампания.

Сегмент Truth (binary uplift) T-learner S-learner
new 0.110 0.126 0.120
returning 0.010 0.018 0.019

Синтетика с истинным гетерогенным эффектом — единственная причина, по которой восстановление вообще можно проверить: на реальных данных ITE не наблюдается никогда, и это фундаментальная проблема causal inference.

Эффект

  • CUPED — та же оценка ATE, стандартная ошибка −26%, CI в 1.35× уже.
  • Экономия трафика — 10k → ~5.6k пользователей на руку при той же мощности.
  • Uplift — T- и S-learner бьют random по AUUC, Qini и uplift@20%.
  • Таргетинг — восстановленный эффект «new ~10× returning» превращает скидки из «всем» в адресные.

Документация

Разбор кейса

Проблема

Стандартный двухвыборочный t-тест отвечает только на «работает ли эффект в среднем» и не использует пред-период. Из-за этого эксперименты требуют больше трафика, чем необходимо, а retention-акции рассылаются всем, тогда как реагирует лишь часть пользователей. Нужны методы, которые снижают дисперсию и оценивают эффект на уровне отдельного пользователя.

Подход

CUPED: Y_adj = Y − θ·(X − mean(X)), где θ = Cov(Y,X)/Var(X) — та же ожидаемая оценка ATE при дисперсии ~(1 − ρ²). Два uplift-лернера на LightGBM: T-learner (модель на каждую руку) и S-learner (treatment как признак), подъём = P(t=1) − P(t=0). Оценка — AUUC, Qini, uplift@20%, ранговая корреляция с латентной τ и по-сегментное восстановление; всё реализовано с нуля на LightGBM, без causalml/econml.

Результат

CUPED не меняет точечную оценку (0.270 → 0.276, в пределах шума), но сжимает стандартную ошибку на ~26% и сужает 95% CI в 1.35× — эксперимент, которому нужно было 10k пользователей на руку, обходится ~5.6k. Оба лернера бьют random по всем метрикам; модель восстанавливает, что «новые» пользователи отвечают ~10× сильнее «возвращающихся», — это сигнал для таргетинга скидок.

−26% Снижение SE
1.35× Сужение 95% CI
10k → 5.6k Пользователей на руку
0.66 corr(τ), S-learner

Аналитика

Данные: github.com/NikitaBoyarkin/causal-uplift: metrics from run.py (reports/metrics.json) on the seeded synthetic randomized experiment (20,000 users, seed=42); regenerate with `uv run --with pandas --with numpy --with scikit-learn --with lightgbm --with matplotlib python run.py`

CUPED: та же оценка ATE, более узкий интервал

Точечная оценка ATE и ширина 95% доверительного интервала для наивной оценки и CUPED на синтетическом рандомизированном эксперименте (20 000 пользователей, seed=42).

0 0.1 0.2 Naive — ATE: 0.27 0.27 CUPED — ATE: 0.28 0.28 Naive — 95% CI width: 0.08 0.08 CUPED — 95% CI width: 0.06 0.06 Naive CUPED Метод Значение ATE 95% CI width
Выводы
  • Точечная оценка не меняется: ATE 0.270 → 0.276 (в пределах шума) — CUPED снижает дисперсию, а не эффект.
  • Ширина 95% CI падает с 0.076 до 0.057 (в 1.35×): эксперименту нужно ~5.6k пользователей на руку вместо 10k при той же мощности.

Восстановление эффекта по сегментам

Истинный бинарный uplift против предсказанного T- и S-лернерами по сегментам. Латентная τ — 0.60 (new) и 0.08 (returning); сигмоида при высоком базовом уровне конверсии сжимает эффект до ~0.11 / 0.01.

0 0.05 0.1 new — Truth: 0.11 0.11 returning — Truth: 0.01 0.01 new — T-learner: 0.13 0.13 returning — T-learner: 0.02 0.02 new — S-learner: 0.12 0.12 returning — S-learner: 0.02 0.02 new returning Сегмент Uplift Truth T-learner S-learner
Выводы
  • Модель восстанавливает, что «новые» реагируют ~10× сильнее «возвращающихся» (0.110 против 0.010) — это сигнал для таргетинга скидок.
  • Предсказание близко к истине в обоих сегментах: 0.120 (S-learner) против 0.110 (truth) для new.

Смотрите также

Карта связей

Проекты, записи и темы, связанные с этим проектом. Наведите на узел, чтобы увидеть название; клик — открыть.