Предсказание оттока — Churn Prediction для аналитика
Что такое Churn и зачем его предсказывать
Churn — отток пользователей, которые перестали пользоваться продуктом. Подробнее о разнице между Retention и Churn — в отдельной статье. Здесь фокус на предсказании: как заранее определить, кто уйдёт, чтобы успеть вмешаться.
Зачем это нужно:
- Удержание дешевле привлечения. Привлечь нового пользователя стоит в 5–7 раз дороже, чем удержать существующего.
- Таргетированные действия. Вместо скидки для всех — скидка для тех, кто вот-вот уйдёт. Экономия бюджета и точечный эффект.
- Прогноз выручки. Если вы знаете, сколько пользователей уйдёт в следующем месяце, можете точнее планировать финансы.
- Понимание причин. Модель показывает, какие факторы влияют на отток — это сигнал для продуктовых изменений.
На собеседованиях churn prediction — одна из самых популярных тем на стыке аналитики и ML. Спрашивают подход, выбор признаков, метрики и что делать с результатами.
Определение churned-пользователя
Перед построением модели нужно чётко определить, кого считать ушедшим. Это не так просто, как кажется.
Подписочные продукты: пользователь отменил подписку или не продлил. Чёткий сигнал.
Бесплатные продукты: пользователь не заходил N дней. Но какое N? 7 дней? 30? 90? Зависит от частоты использования продукта.
Подход: постройте распределение интервалов между сессиями. Если 90% пользователей возвращаются в течение 14 дней, то отсутствие 14+ дней — разумный порог.
-- Распределение интервалов между сессиями
WITH user_sessions AS (
SELECT user_id,
created_at,
LAG(created_at) OVER (
PARTITION BY user_id ORDER BY created_at
) AS prev_session
FROM events
WHERE event_name = 'session_start'
),
gaps AS (
SELECT user_id,
EXTRACT(DAY FROM created_at - prev_session) AS days_gap
FROM user_sessions
WHERE prev_session IS NOT NULL
)
SELECT days_gap,
COUNT(*) AS frequency,
ROUND(100.0 * COUNT(*) / SUM(COUNT(*)) OVER (), 2) AS pct
FROM gaps
GROUP BY days_gap
ORDER BY days_gap;Признаки для модели оттока
Качество модели на 80% определяется признаками (features). Вот категории, которые обычно работают.
Активность
- Число сессий за последние 7/14/30 дней
- Частота визитов (сессий в неделю)
- Время в продукте за период
- Число целевых действий (покупок, ответов, публикаций)
- Тренд активности: растёт, стабильна, падает
Динамика
- Изменение активности: сравнение последней недели с предыдущей
- Дни с последнего визита (recency)
- Максимальный gap между сессиями
Профиль пользователя
- Время жизни (дней с регистрации)
- Канал привлечения
- Устройство / платформа
- Был ли на онбординге
- Подписка (тип, срок)
Вовлечённость
- Число использованных фич
- Глубина сессий (сколько экранов/действий за визит)
- Использование ключевых фич (тех, что коррелируют с Retention)
- Социальные взаимодействия (если есть)
Монетизация
- Потратил ли деньги
- Сумма покупок
- Дней с последней покупки
Простой подход: правила (rules-based)
Не всегда нужна ML-модель. Для начала можно построить систему на правилах.
import pandas as pd
def churn_risk_score(user):
"""Простая скоринговая модель на правилах."""
score = 0
# Давно не заходил
if user['days_since_last_visit'] > 14:
score += 3
elif user['days_since_last_visit'] > 7:
score += 2
elif user['days_since_last_visit'] > 3:
score += 1
# Активность падает
if user['sessions_last_7d'] < user['sessions_prev_7d'] * 0.5:
score += 2
# Мало использует фичи
if user['features_used'] < 3:
score += 1
# Никогда не платил
if user['total_purchases'] == 0:
score += 1
return score # 0-7: чем больше, тем выше рискПлюсы: прозрачно, быстро внедрить, не нужен ML. Минусы: субъективные пороги, не учитывает взаимосвязи между факторами.
ML-подход
Когда данных достаточно, модель найдёт паттерны лучше ручных правил.
Подготовка данных
Задача — бинарная классификация: churned (1) vs active (0).
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
# Формируем датасет
# Каждая строка — пользователь, таргет — churned (0/1)
df = pd.read_csv('user_features.csv')
features = [
'days_since_last_visit', 'sessions_last_7d', 'sessions_last_30d',
'activity_trend', 'features_used', 'session_depth_avg',
'days_since_registration', 'total_purchases', 'is_premium'
]
X = df[features]
y = df['churned']
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42, stratify=y
)
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)Логистическая регрессия
Хороший baseline. Интерпретируемая, быстрая, устойчивая.
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import classification_report, roc_auc_score
model_lr = LogisticRegression(random_state=42, class_weight='balanced')
model_lr.fit(X_train_scaled, y_train)
y_pred = model_lr.predict(X_test_scaled)
y_prob = model_lr.predict_proba(X_test_scaled)[:, 1]
print(classification_report(y_test, y_pred))
print(f"ROC AUC: {roc_auc_score(y_test, y_prob):.3f}")class_weight='balanced' важен — обычно churned-пользователей меньше, чем активных, и модель без балансировки будет предсказывать «не уйдёт» для всех.
Random Forest
Ловит нелинейные зависимости, не требует масштабирования, показывает важность признаков.
from sklearn.ensemble import RandomForestClassifier
model_rf = RandomForestClassifier(
n_estimators=200,
max_depth=10,
class_weight='balanced',
random_state=42
)
model_rf.fit(X_train, y_train)
# Важность признаков
importance = pd.DataFrame({
'feature': features,
'importance': model_rf.feature_importances_
}).sort_values('importance', ascending=False)
print(importance)Типичный топ-3 важных признаков: days_since_last_visit, activity_trend, sessions_last_7d. Если у вашей модели так — всё логично.
Метрики качества
Для churn prediction важны:
| Метрика | Что показывает | Когда критична |
|---|---|---|
| ROC AUC | Общая способность разделять классы | Всегда (baseline метрика) |
| Precision | Из предсказанных churned — сколько реально ушли | Когда действие дорогое (звонок менеджера) |
| Recall | Из реально ушедших — скольких поймали | Когда потеря клиента дорога |
| F1 | Баланс Precision и Recall | Когда нужен компромисс |
На практике чаще смотрят Precision@K: если вы можете позвонить 100 пользователям в день — какой процент из топ-100 по скору реально уйдёт?
Что делать с предсказаниями
Модель выдала вероятность оттока для каждого пользователя. Дальше:
1. Сегментируйте по риску.
- Высокий (>0.7): агрессивные действия — персональное предложение, звонок
- Средний (0.4–0.7): лёгкие nudge — пуш, email, скидка
- Низкий (<0.4): ничего не делать (не тратить ресурсы)
2. Выберите действие. Зависит от продукта:
- Скидка или бонус
- Персональная рекомендация контента
- Push-уведомление с ценным контентом
- Звонок менеджера (для B2B)
- Email-цепочка реактивации
3. Измерьте эффект. Запустите A/B-тест: группа с интервенцией vs. контрольная группа. Сравните churn rate. Без теста вы не узнаете, помогло ли действие или пользователи остались бы и без него.
4. Обновляйте модель. Поведение пользователей меняется. Модель, обученная полгода назад, может деградировать. Пересчитывайте признаки и переобучайте хотя бы раз в квартал.
Подводные камни
Утечка данных (data leakage). Если в признаках есть информация из будущего — модель будет идеально работать на тесте и бесполезна в продакшене. Пример: «пользователь удалил аккаунт» — это следствие churn, а не причина.
Дисбаланс классов. Если churned = 5% выборки, модель предскажет «не уйдёт» для всех и получит 95% accuracy. Используйте class_weight='balanced', oversampling (SMOTE) или оптимизируйте по AUC/F1.
Неправильный горизонт. Предсказывать churn через 30 дней на основе данных за 7 — рискованно. Чем дальше горизонт, тем ниже точность. Начните с 7–14 дней.
Подробнее о когортном анализе и линейной регрессии — в отдельных статьях.
Вопросы с собеседований
— Как бы вы подошли к задаче предсказания оттока? — Определил бы churned-пользователя (порог неактивности). Собрал признаки: активность, динамика, профиль, монетизация. Начал с логрегрессии как baseline, потом попробовал Random Forest. Оценил по ROC AUC и Precision@K. По результатам — сегментация и A/B-тест интервенций.
— Какие признаки самые важные для churn prediction? — Обычно: days since last visit (recency), тренд активности (падает/растёт), частота сессий за последние 7 дней. Это фичи, связанные с недавним поведением — они сильнее предсказывают отток, чем статичные характеристики типа канала привлечения.
— Почему accuracy — плохая метрика для churn? — Из-за дисбаланса классов. Если ушли 5% пользователей, модель «никто не уйдёт» даёт 95% accuracy. Но она бесполезна. Нужны ROC AUC, Precision, Recall, F1.
— Что такое data leakage и как его избежать? — Утечка — когда в признаках есть информация из будущего или напрямую связанная с таргетом. Избежать: строить признаки только из данных до момента предсказания, не включать следствия оттока (удаление аккаунта, отмена подписки) в фичи.
— Как оценить бизнес-эффект модели? — A/B-тест: группе с высоким скором отправляем интервенцию, контрольной — нет. Сравниваем churn rate. Считаем ROI: сколько сохранили пользователей × LTV − стоимость интервенции.
FAQ
Нужен ли ML для предсказания оттока или хватит правил?
Зависит от масштаба. Для MVP или маленького продукта правила работают отлично: «не заходил 14 дней + активность падала» — уже полезный сигнал. ML оправдан, когда у вас тысячи пользователей, десятки признаков и нужна точная приоритизация.
Как часто переобучать модель?
Раз в квартал — хороший ритм. Чаще — если у продукта быстро меняется аудитория или функциональность. Обязательно мониторьте метрики модели в продакшене: если ROC AUC падает — пора переобучать.
Какую модель выбрать — логрегрессию или Random Forest?
Начните с логистической регрессии — она быстрее, интерпретируемее, и часто даёт сравнимое качество. Random Forest попробуйте вторым шагом — если он даёт значимый прирост AUC (>0.02–0.03), используйте его. Для собеседования важнее объяснить выбор, чем угадать «правильную» модель.
Потренируйте вопросы по предсказанию оттока на реальных задачах — откройте тренажёр. 1500+ вопросов, которые спрашивают на собеседованиях аналитика. Бесплатно.