← К портфолио Churn Prediction — Leakage-Free Retention Model preview
Стек
PythonLightGBMscikit-learnpandas / NumPymatplotlibpytestuv
Эффект
  • Chronological snapshot split (train/val/test) — no future activity leaks into training
  • Churn label = a future 30-day inactivity window for recently active users only
  • Decision metric recall@top-10% = 0.53, lift@top-10% = 3.07x
  • LightGBM Brier 0.068 vs 0.099 for the balanced logistic baseline
Исходники Смотреть на GitHub → Обновлено: Sep 18, 2026

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-спенде.

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

Разбор кейса

Проблема

Модели оттока часто оценивают не так, как их используют: случайный train/test-сплит подкладывает будущую активность пользователя в обучение, а метрика (AUC) не отвечает на вопрос, ради которого модель строят — кого из топ-риска стоит трогать. Нужна модель, где схема оценки совпадает с продом.

Подход

Признаки считаются 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) — случайный сплит был бы скрытой утечкой. Решение принимается по recall@top-decile и lift@top-decile, а не по AUC; SHAP — через нативный TreeSHAP LightGBM без пакета shap.

Результат

На тестовом снимке LightGBM и логистический бейзлайн почти совпадают по AUC (0.904 против 0.917), но LightGBM заметно лучше калиброван (Brier 0.068 против 0.099). В топ-10% самых рискующих модель ловит 53% реальных отточников — lift 3.07x к случайному отбору. Честный вывод: сильный recency-признак делает lift скромным, ценность проекта — в схеме без утечек и в бизнес-метрике.

0.53 Recall@top-10%
3.07× Lift@top-10%
0.904 ROC-AUC
0.068 Brier

Аналитика

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

LightGBM против логистического бейзлайна

ROC-AUC, PR-AUC, recall@top-10% и Brier на тестовом снимке (2024-03-15). ROC-AUC и PR-AUC близки; разница проявляется в калибровке — главной метрике, когда скор управляет retention-бюджетом.

0 0.5 ROC-AUC — LightGBM: 0.9 0.9 PR-AUC — LightGBM: 0.81 0.81 Recall@top-10% — LightGBM: 0.53 0.53 Brier — LightGBM: 0.07 0.07 ROC-AUC — LogReg (balanced): 0.92 0.92 PR-AUC — LogReg (balanced): 0.83 0.83 Recall@top-10% — LogReg (balanced): 0.54 0.54 Brier — LogReg (balanced): 0.1 0.1 ROC-AUC PR-AUC Recall@top-10% Brier Метрика Значение LightGBM LogReg (balanced)
Выводы
  • ROC-AUC почти ничья (0.904 против 0.917), но по калибровке LightGBM заметно лучше: Brier 0.068 против 0.099.
  • В топ-10% самых рискующих модель ловит 53% реальных отточников — это lift 3.07× к случайному отбору (у бейзлайна 3.08× при худшей калибровке).

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

Карта связей

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