Головна▸Статті▸Fintech та бізнес ML

Прогнозування відтоку

Побудова систем прогнозування відтоку - survival analysis, feature engineering з поведінки, обробка class imbalance та retention interventions.

mysimulator teamОновлено 2026-01≈ 7 хв читання▶ Open the simulation

Прогнозування відтоку (churn prediction) ідентифікує клієнтів, які ймовірно підуть, до того як вони це зроблять. Це один з ML застосувань з найвищим ROI - утримання існуючих клієнтів коштує в 5-25 разів менше ніж залучення нових. Хороші churn моделі дозволяють проактивні retention кампанії, націлені на правильних клієнтів у правильний час.

Де це використовується

Прогнозування відтоку критичне в subscription та service бізнесах:

Компанії: Великі телеком провайдери, всі subscription бізнеси, loyalty програми.

Типові дані

Аспект Типові значення
Клієнти 100K-10M
Churn rate 2%-15% щомісяця
Кількість фіч 50-500
Горизонт прогнозу 30-90 днів
Історичні дані 1-3 роки

Джерела даних: - Дані використання (логіни, транзакції, engagement) - Історія білінгу та платежів - Взаємодії з підтримкою - Інформація про акаунт та tenure - Marketing touchpoints - Зовнішні дані (демографія, ринок)

Що ви робите на практиці

  1. Визначте churn - Що саме означає churn для вашого бізнесу?
  2. Встановіть горизонт прогнозу - На скільки вперед прогнозувати?
  3. Створіть observation windows - Історичні фічі та періоди міток
  4. Інженерія фіч - Тренди використання, engagement, поведінкові сигнали
  5. Обробіть imbalance - Churn типово minority class
  6. Натренуйте модель - Classification або survival модель
  7. Калібруйте ймовірності - Точні scores для бізнес-рішень
  8. Оцініть бізнес-вплив - Збережений дохід, не тільки AUC
  9. Деплойте retention actions - Тригеріть кампанії на основі ризику
  10. Виміряйте ефективність інтервенцій - Чи зменшили дії churn?

Спочатку бейзлайн

Почніть з простих правил перед ML:

# Rule-based бейзлайн
def simple_churn_rules(customer):
    """Базові індикатори churn."""
    risk_score = 0

    # Немає активності за останні 30 днів
    if customer.days_since_last_activity > 30:
        risk_score += 3

    # Використання падає
    if customer.usage_trend_30d < -0.3:
        risk_score += 2

    # Скарги в підтримку
    if customer.complaints_last_90d > 2:
        risk_score += 2

    # Проблеми з платежами
    if customer.failed_payments_last_90d > 0:
        risk_score += 2

    return risk_score >= 4  # Поріг високого ризику

Чому rule бейзлайн: - Доменні експерти знають ключові churn сигнали - Інтерпретований і легко валідувати - Встановлює що ML має побити - Може бути достатнім для малого масштабу

Feature Engineering

Churn фічі типово походять з поведінкових патернів:

Категорія Фічі
Engagement Частота логінів, тривалість сесій, використання фіч
Тренди Зміна використання week-over-week, падаючий engagement
Tenure Вік акаунту, тривалість підписки, історія апгрейдів
Білінг Затримки платежів, зміни плану, історія знижок
Підтримка Кількість тікетів, типи скарг, час вирішення
Соціальне Зроблені referrals, соціальні зв'язки, community

Temporal feature engineering:

def create_churn_features(customer_id, observation_date):
    """Створити фічі для прогнозування churn."""
    features = {}

    # Activity windows
    for window in [7, 14, 30, 60, 90]:
        activity = get_activity(customer_id, 
                               end=observation_date,
                               days=window)
        features[f'logins_{window}d'] = activity.login_count
        features[f'sessions_{window}d'] = activity.session_count
        features[f'duration_{window}d'] = activity.total_duration

    # Тренди (порівняння нещодавнього з історичним)
    recent = get_activity(customer_id, end=observation_date, days=14)
    historical = get_activity(customer_id, 
                              end=observation_date - timedelta(14),
                              days=14)

    if historical.login_count > 0:
        features['login_trend'] = (
            recent.login_count - historical.login_count
        ) / historical.login_count
    else:
        features['login_trend'] = 0

    # Recency
    last_activity = get_last_activity(customer_id, observation_date)
    features['days_since_activity'] = (
        observation_date - last_activity
    ).days

    # Білінг
    features['payment_failures_90d'] = count_payment_failures(
        customer_id, observation_date, days=90
    )

    return features

Обробка Class Imbalance

Churn типово 2-10% клієнтів - сильний imbalance:

from imblearn.over_sampling import SMOTE
from imblearn.under_sampling import RandomUnderSampler
from imblearn.pipeline import Pipeline

# Опція 1: SMOTE oversampling
smote = SMOTE(sampling_strategy=0.3)
X_resampled, y_resampled = smote.fit_resample(X_train, y_train)

# Опція 2: Class weights
model = XGBClassifier(
    scale_pos_weight=len(y_train[y_train==0]) / len(y_train[y_train==1])
)

# Опція 3: Комбінований підхід
pipeline = Pipeline([
    ('under', RandomUnderSampler(sampling_strategy=0.5)),
    ('over', SMOTE(sampling_strategy=0.8))
])

# Опція 4: Cost-sensitive threshold
# Не ресемплювати, налаштувати поріг рішення на основі витрат

Оптимізація порогу:

def optimize_threshold(y_true, y_proba, 
                       cost_fn=1, cost_fp=0.1, cost_tp=-0.5):
    """Знайти поріг що мінімізує бізнес-витрати."""
    thresholds = np.arange(0.1, 0.9, 0.01)
    costs = []

    for thresh in thresholds:
        y_pred = (y_proba >= thresh).astype(int)

        fn = ((y_true == 1) & (y_pred == 0)).sum()  # Пропущені churners
        fp = ((y_true == 0) & (y_pred == 1)).sum()  # Фальшиві тривоги
        tp = ((y_true == 1) & (y_pred == 1)).sum()  # Спіймані churners

        total_cost = fn * cost_fn + fp * cost_fp + tp * cost_tp
        costs.append(total_cost)

    best_idx = np.argmin(costs)
    return thresholds[best_idx]

Підходи моделей

Підхід Плюси Мінуси Коли використовувати
Logistic Regression Інтерпретований, швидкий Обмежені патерни Бейзлайн, regulated
Gradient Boosting Найкраща точність Менш інтерпретований Більшість випадків
Survival Analysis Обробляє censoring, time-to-event Складніший Timing підписки
Neural Networks Sequence патерни Потребує більше даних Поведінкові sequences

Приклад Gradient Boosting:

from lightgbm import LGBMClassifier

model = LGBMClassifier(
    n_estimators=200,
    learning_rate=0.05,
    num_leaves=31,
    class_weight='balanced',
    random_state=42
)

model.fit(X_train, y_train)

# Probability predictions для risk scoring
churn_proba = model.predict_proba(X_test)[:, 1]

Survival Analysis підхід:

from lifelines import CoxPHFitter

# Підготувати дані з duration та event
df['duration'] = (df['observation_date'] - df['signup_date']).dt.days
df['churned'] = df['churn_date'].notna().astype(int)

# Cox Proportional Hazards
cph = CoxPHFitter()
cph.fit(df[features + ['duration', 'churned']], 
        duration_col='duration', 
        event_col='churned')

# Ймовірність виживання на 30 днів
survival_30d = cph.predict_survival_function(
    df[features], times=[30]
).T
churn_prob_30d = 1 - survival_30d

Оцінка та метрики

Метрика Що вимірює Типова ціль
AUC-ROC Якість ранжування > 0.75
Precision at K Якість топ-K ризикованих > 50%
Recall at threshold Спіймані churners > 60%
Lift at decile 1 Покращення над random > 3x
Expected value Вплив на дохід Позитивний ROI

Бізнес-орієнтована оцінка:

def calculate_lift_chart(y_true, y_proba, n_bins=10):
    """Розрахувати lift по децилях."""
    df = pd.DataFrame({'true': y_true, 'proba': y_proba})
    df['decile'] = pd.qcut(df['proba'], n_bins, labels=False)

    lift = df.groupby('decile').agg({
        'true': ['sum', 'count', 'mean']
    })
    lift.columns = ['churners', 'total', 'churn_rate']
    lift['lift'] = lift['churn_rate'] / y_true.mean()

    return lift

# Топ дециль має мати найвищу концентрацію churners
lift_chart = calculate_lift_chart(y_test, churn_proba)
print(f"Lift у топ децилі: {lift_chart.loc[9, 'lift']:.2f}x")

Режими відмов та чеклист налагодження

Чеклист для продакшну

Перед деплоєм: - [ ] Визначення churn валідоване з бізнесом - [ ] Feature pipeline gracefully обробляє missing data - [ ] Модель калібрована для accuracy ймовірностей - [ ] Поріг оптимізований для бізнес-витрат - [ ] Intervention стратегія визначена на risk tier

Після деплою: - [ ] Прогнози генеруються за розкладом (daily/weekly) - [ ] Risk scores пушаться в CRM/marketing системи - [ ] Продуктивність моделі моніториться vs actuals - [ ] Ефективність інтервенцій відстежується - [ ] Feature drift моніториться

Інтеграція інтервенцій: - [ ] Risk tiers визначені (high/medium/low) - [ ] Retention actions на tier (знижка, outreach, контент) - [ ] Holdout група для вимірювання впливу інтервенції - [ ] Feedback loop до моделі (що спрацювало?)

Вимірювання впливу інтервенцій

Запуск retention кампаній вимагає вимірювання справжнього впливу:

def measure_intervention_impact(treatment_group, control_group):
    """Порівняти churn rates між групами."""
    treatment_churn = treatment_group['churned'].mean()
    control_churn = control_group['churned'].mean()

    lift = (control_churn - treatment_churn) / control_churn

    # Статистична значущість
    from scipy.stats import chi2_contingency
    contingency = pd.crosstab(
        pd.concat([treatment_group, control_group])['group'],
        pd.concat([treatment_group, control_group])['churned']
    )
    chi2, p_value, _, _ = chi2_contingency(contingency)

    return {
        'treatment_churn': treatment_churn,
        'control_churn': control_churn,
        'relative_reduction': lift,
        'p_value': p_value
    }

Інструменти та стек

Категорія Інструменти
Моделювання LightGBM, XGBoost, scikit-learn, lifelines
Feature engineering Featuretools, кастомні пайплайни
Оркестрація Airflow, Prefect, dbt
Деплоймент MLflow, кастомні scoring jobs
Інтеграція CRM (Salesforce), marketing automation

Приклад міні-кейсу

Сценарій: SaaS компанія з 50K клієнтів, 8% місячний churn, $100 середній місячний дохід.

Підхід: 1. Визначення: Немає логіну 30 днів після дати білінгу 2. Фічі: 120 фіч з usage, billing, support 3. Модель: LightGBM з class weights 4. Поріг: Оптимізований для 3:1 FN:FP cost ratio

Результати: - AUC: 0.82 - Lift у топ децилі: 4.2x - Precision у топ 10%: 31% (vs 8% baseline) - Інтервенція: 15% знижка для high-risk клієнтів

Бізнес-вплив: - 200 high-risk клієнтів ідентифіковано щомісяця - 40% acceptance rate знижки - 25% зменшення churn серед intervened - Чистий збережений дохід: $12K/місяць (після витрат на знижку)

Пов'язані сторінки

Додаткове читання

Спробуйте наживо

Дослідіть пов'язану модель на практиці: відкрийте Customer Churn Predictor — Survival Curve Live і змінюйте параметри під час роботи. Усе лишається у вашому браузері.

▶ Відкрити симуляцію Customer Churn Predictor — Survival Curve Live

Що ви знайшли?

Додати кроки відтворення (опційно)