Churn Prediction — Leakage-Free Retention Model
Контекст
Модель оттока для подписочного продукта. Ценность проекта — не алгоритм, а дисциплина: признаки считаются «as-of» на дату снимка, целевая переменная — будущее окно неактивности, а разбиение хронологическое, поэтому модель оценивается так, как её использовали бы в проде. Это тот же принцип, что и в A/B-анализе: «нет утечки из будущего в моделируемый момент».
Данные и метод
Данные синтетические и детерминированные (seed = 42): 12 000 пользователей регистрируются с июня 2023 по январь 2024, канал задаёт tenure (экспоненциальное время жизни), тариф — вероятность дневной активности; активность слегка затухает к оттоку, доля оттока ~16% на снимок.
Признаки и метка
- Признаки as-of — recency, активность за 7/14/30 дней, tenure, недавний тренд, средние сессии + категориальные
channel/device/country/plan. - Метка без утечки — отток = нет активности в
[snapshot, snapshot+30d]у пользователя, активного предыдущие 30 дней. Давно «мёртвые» пользователи исключены, а не помечены: предсказывать на призраках — не задача.
Сплит и метрика
- Хронологический сплит — train (2024-01-15) → val (2024-02-15) → test (2024-03-15). Случайный сплит подложил бы будущую активность пользователя в обучение и его прошлое в тест — это скрытая утечка, и ради её устранения проект и существует.
- Метрика бизнеса вперёд — ROC-AUC и PR-AUC считаются, но решение принимают по recall@top-decile и lift@top-decile: если retention работает с топ-10% самых рискующих, сколько реальных отточников мы ловим.
Модель и тесты
- SHAP — нативный
predict_proba(pred_contrib=True)LightGBM (TreeSHAP без зависимости от пакетаshap). Доминируетrecency_days. - Бейзлайн — сбалансированная логистическая регрессия.
- Тесты — 5 pytest: баланс, отсутствие утечек, корректность recency, «модель бьёт бейзлайн».
| Метрика (test snapshot) | LightGBM | LogReg (balanced) |
|---|---|---|
| ROC-AUC | 0.904 | 0.917 |
| PR-AUC | 0.809 | 0.825 |
| Recall@top-10% | 0.53 | 0.54 |
| Lift@top-10% | 3.07× | 3.08× |
| Brier (калибровка) | 0.068 | 0.099 |
Запуск
# Python >=3.10. Deps: pandas, numpy, scikit-learn, lightgbm, matplotlib.
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 + evaluation.png (ROC, PR, SHAP bar).
Что нашли
AUC почти ничья (синтетические признаки почти линейны, поэтому логистика конкурентна), но LightGBM значительно лучше калиброван (Brier 0.068 против 0.099) — а это важно, когда скор управляет retention-бюджетом. Честный вывод: сильный recency-признак делает lift скромным; ценность проекта — в схеме без утечек и в бизнес-метрике, а не в «трофее» GBM.
Эффект
- Хронологический сплит по снимкам — нет утечки будущего в обучение.
- Метка из будущего окна — не предсказываем на давно ушедших пользователях.
- Бизнес-метрика первой — recall@top-10% 0.53, lift@top-10% 3.07×.
- Калибровка — Brier 0.068 (LightGBM) против 0.099 (LogReg): скор пригоден для решений о retention-спенде.