Почему churn-модели часто ошибаются еще до обучения
Модель оттока кажется понятной постановкой: есть пользователи, часть уходит, нужно предсказать риск ухода заранее. Но именно в churn prediction очень легко перепутать причину с последствием. В признаки могут попасть сигналы, которые становятся видны уже после фактического ухода или прямо на его границе. В итоге модель учится не распознавать ранний риск, а просто читать уже почти завершившийся процесс ухода.
Снаружи это может выглядеть как высокая метрика, но для бизнеса пользы почти не будет: модель предупреждает слишком поздно.
Что на самом деле хочет предсказать churn-модель
$$ P(Churn = 1 \mid X_{t-k:t}) $$Хорошая модель оттока должна оценивать вероятность ухода на основе истории признаков в окне времени до текущего момента, а не использовать информацию, появившуюся уже после наступления фактического churn.
Churn = 1— факт ухода пользователяX_{t-k:t}— признаки и история поведения до момента прогнозаt— текущий момент принятия решенияk— длина исторического окна для признаков
Главная идея здесь в том, что churn — это всегда прогностическая задача во времени. Если время в постановке потерялось, велика вероятность leakage.
Почему риск и последствие легко перепутать
Например, резкое отсутствие логинов в последние дни может быть и ранним сигналом ухода, и уже фактическим последствием ухода — в зависимости от того, как именно определен target и на каком горизонте принимается решение. То же самое с обращениями в поддержку, отключением подписки, изменением частоты покупок. Поэтому признаки для churn-модели всегда нужно читать через вопрос: доступно ли это значение в момент, когда мы еще можем повлиять на пользователя?
Именно этот вопрос делает churn-проект честным или бессмысленным.
Как показать задачу на Python
import pandas as pd # создаем простой пример поведенческих признаков для риска оттока
from sklearn.linear_model import LogisticRegression # используем интерпретируемую модель для классификации риска
frame = pd.DataFrame({ # задаем признаки, доступные до момента решения
'sessions_7d': [1, 2, 3, 4, 5, 6], # активность за последние 7 дней
'days_since_last_visit': [14, 10, 7, 4, 2, 1], # сколько дней прошло с последнего визита
'tickets_30d': [3, 2, 1, 1, 0, 0], # обращения в поддержку за последний месяц
'churned': [1, 1, 1, 0, 0, 0], # целевой признак ухода на целевом горизонте
})
X = frame[['sessions_7d', 'days_since_last_visit', 'tickets_30d']] # формируем матрицу безопасных признаков
y = frame['churned'] # сохраняем target отдельно
model = LogisticRegression(max_iter=2000) # строим базовую churn-модель
model.fit(X, y) # обучаем классификатор оценивать риск ухода
print(model.predict_proba(X)[:, 1].round(3).tolist()) # получаем вероятности оттока для пользователейХорошая churn-модель начинается не с алгоритма, а с правильного времени в постановке. Если это время учтено честно, дальше уже можно обсуждать метрики, признаки и actionability результата.