Мы столкнулись с задачей: у SaaS-продукта с $1M MRR отток (churn) составлял 5% в месяц. Каждый процент снижения — это $120K дополнительного ARR в год. Но без точной модели удержание превращается в стрельбу вслепую: скидки всем подряд сжигают маржу. Churn prediction решает это — модель выявляет клиентов с высоким риском ухода до того, как они уйдут. Мы строим систему, которая на практике снижает отток на 20%.
Проблемы, которые решаем
Размытый таргет. В non-contractual сценариях (e-commerce, игры) нет явной метки ухода — нужно определить порог неактивности. Например, если клиент не совершал покупку 90 дней — считаем ушедшим. Выбор порога критичен: при 30 днях метка есть у 20% клиентов, при 90 — у 5%.
Несбалансированные классы. 2-10% уходящих против 90% остающихся. Без коррекции модель даёт 90% accuracy, но ноль recall по уходящим.
Feature engineering. RFM-метрики — основа, но нужны ещё тренды (изменение активности за 30 дней), adoption rate фич, тикеты поддержки. Мы используем rolling window агрегации и diff-фичи.
Как мы это делаем: стек и кейс
Стек: LightGBM (baseline) — LightGBM в 10 раз быстрее LSTM на табличных данных при сравнимом качестве. CatBoost для категориальных фич, LSTM если критична последовательность событий. Feature store — PostgreSQL с pgvector для эмбеддингов. MLflow для экспериментов, SHAP для интерпретации.
Развернутый кейс из нашей практики: Клиент — B2B SaaS с 50K юзеров. Baseline LightGBM дал PR-AUC 0.31. После добавления trend features (изменение частоты логинов за 30 дней) — 0.41, +32%. Добавление sequence модели (LSTM на последовательности событий) подняло до 0.49, но на 4x latency. В итоге продакшн — ансамбль LightGBM + LSTM с каскадным скорингом.
Как определить отток в non-contractual сценарии?
Определите пороговый период неактивности, после которого клиент считается ушедшим. Мы выбираем X на основе анализа распределения интервалов между покупками. Типичные значения: 60-90 дней для B2B SaaS, 90-180 для e-commerce. Неверный выбор ведет к шуму в целевой переменной.
Почему LightGBM — хороший baseline для churn prediction?
LightGBM устойчив к пропускам, работает с категориями (при правильном кодировании), учитывает нелинейные зависимости. На стандартных задачах оттока он обгоняет логистическую регрессию по AUC-ROC на 0.15–0.25 и при этом быстрее XGBoost в 2-3 раза.
Разработка и развертывание модели
Feature Engineering
RFM-метрики (наиболее важные предикторы):
- Recency: дней с последнего действия/транзакции
- Frequency: количество сессий/покупок за 30/90/180 дней
- Monetary: сумма трат за период
Поведенческие фичи:
- Trend features: рост/снижение активности за последние 30 дней vs. предыдущие 30
- Feature adoption rate: какой % ключевых функций продукта использует клиент
- Support tickets: количество обращений, тип, NPS после решения
Контрактные/демографические:
- Срок с момента онбординга
- Тип тарифного плана
- Сегмент (SMB / Enterprise)
- Канал привлечения
Выбор алгоритма
| Алгоритм | Когда использовать | Точность | Интерпретируемость |
|---|---|---|---|
| Logistic Regression | Baseline, нужна интерпретируемость | Средняя | Высокая |
| LightGBM / XGBoost | Табличные данные, нет time series | Высокая | Средняя (SHAP) |
| CatBoost | Много категориальных фич | Высокая | Средняя |
| LSTM / Transformer | Последовательности событий важны | Очень высокая | Низкая |
Рекомендация: начать с LightGBM как baseline, добавить Sequence Model если поведенческие паттерны важны.
Работа с несбалансированными классами
Методы борьбы с дисбалансом включают использование class weights (class_weight='balanced' в sklearn) — простейший fix; SMOTE генерирует синтетические примеры minority класса, но может внести шум; Focal Loss в нейросетях downweights easy examples; подбор порога классификации по Precision-Recall curve (не 0.5) — бесплатный способ повысить Precision@K. Для оценки используем F1-score (взвешенный) как основную метрику, AUC-ROC для ранжирования, Precision@K для маркетинга — точность среди топ-K клиентов по риску наиболее важна.
Deployment и использование
Batch scoring: еженедельный запуск модели по всей клиентской базе. Результат — таблица с churn probability для каждого клиента. Сегментация: high risk (>0.7), medium risk (0.4-0.7), low risk (<0.4).
Real-time scoring: API endpoint POST /score, <100 мс ответ, обновление скора в CRM в реальном времени.
Удержание по сегментам:
- High risk: личный звонок от Customer Success или скидка
- Medium risk: автоматизированная email-кампания с value reminder
- Low risk: без действий (не тратить ресурсы)
Оценка бизнес-эффекта
Uplift modeling — правильный способ измерить реальную ценность системы. Обычный A/B тест: 50% high-risk клиентов получают удержание (treatment), 50% — нет (control). Измеряем разницу в churn rate. Компании, использующие churn prediction, снижают отток на 15-20%. Средняя экономия от внедрения — $30–50K на 10K клиентов.
Процесс и сроки работ
Процесс работы
- Аналитика: сбор и очистка данных, определение churn-определения, анализ распределения.
- Feature engineering: RFM, тренды, адопшен фич, контрактные данные.
- Моделирование: baseline (LightGBM), эксперименты (CatBoost, LSTM), подбор порогов.
- Тестирование: offline (AUC, F1, Precision@K), online A/B uplift test.
- Деплой: batch scoring weekly, real-time API (<100ms), интеграция с CRM.
- Мониторинг: дрейф данных, дрейф модели, автоматический перезапуск.
Что входит в работу
- Отчёт по определению churn (выбор таргета)
- Baseline-модель (LightGBM) + SHAP-отчёт
- Документация фичей и пайплайна
- Интеграция batch scoring в вашу CRM
- Обучение команды (2 часа)
- Поддержка 3 месяца после деплоя
Сроки ориентировочно
Первая модель с базовыми RFM-фичами — 2-3 недели. Полноценная система с feature store, мониторингом дрейфа и CRM-интеграцией — 8-10 недель. Мы — команда с 5+ лет опыта в ML-продакшене, 30+ успешных проектов по churn prediction. Свяжитесь, чтобы мы оценили ваш проект и предложили точные сроки. Получите консультацию по внедрению churn prediction.
Пример кода для расчёта RFM-фич
import pandas as pd
def rfm_features(transactions, as_of_date):
"""Расчёт Recency, Frequency, Monetary для каждого клиента."""
rfm = transactions.groupby('customer_id').agg(
recency=('transaction_date', lambda x: (as_of_date - x.max()).days),
frequency=('transaction_id', 'nunique'),
monetary=('amount', 'sum')
).reset_index()
return rfm







