Как ответить
Проект — прогнозирование оттока клиентов для телеком-оператора. Я отвечал за весь пайплайн: от выгрузки до развертывания модели через API. Данные хранились в PostgreSQL, таблица subscribers с 500k строк и 34 признаками: демография, тариф, история платежей, обращения в поддержку.
Выгрузка шла через DBI::dbGetQuery — сразу фильтровал по дате, чтобы не тащить всё. Выборка — случайная стратифицированная по тарифам (пропорция оттока сохранена).
Предобработка:
- Пропуски — в поле
income(~7%) заменил на медиану по тарифу, вchurn_reason— мода. - Выбросы — по длительности звонков: отсекал >99.9 перцентиля (явно ошибочные).
- Признаки — добавил
avg_call_duration,support_calls_per_month,tenure_bin(квартили). Категориальные кодировал target encoding с кросс-валидацией.
Код предобработки выглядел так:
library(tidyverse)
library(data.table)
raw <- dbGetQuery(con, "SELECT * FROM subscribers WHERE date >= '2023-01-01'")
setDT(raw)
raw[, income := fifelse(is.na(income), median(income, na.rm = TRUE), income), by = tariff]
raw[, churn_reason := fcoalesce(churn_reason, 'unknown')]
raw[, avg_call_duration := total_call_duration / total_calls]Модели: логистическая регрессия (baseline) и XGBoost (финальная). Гиперпараметры подбирал через caret::train с 5-кратной стратифицированной кросс-валидацией. Лучшая модель — XGBoost с max_depth=6, eta=0.05, nrounds=200. ROC-AUC на тесте — 0.87, precision@top10% — 0.62.
Результаты завернул в R Plumber — эндпоинт принимает JSON с признаками клиента и возвращает вероятность оттока. Контейнеризовали в Docker, выкатили на staging. Позже модель переписали на Python из-за интеграции с микросервисами, но R-прототип показал бизнесу ценность за 2 недели.