Условие
Имеется выборка по клиентам со списком признаков:
ID, SEX, CHILD_BOOL, REALTY_BOOL, HAVE_ACCOUNT_BOOL, EMAIL_BOOL, DCI, PROFIT_FAMILY, UCI, FOREIGN_PASSPORT_BOOL, SIML, EDUCATION, TRANSPORT_AMOUNT, target
Где target — бинарный флаг (1/0). Любым выбранным методом постройте модель, прогнозирующую target. Обоснуйте выбор по максимально возможному количеству критериев. Дополнительно: стабилен ли ваш прогноз? Не переобучили ли вы модель? Объясните почему.
Задача проверяет не «получите AUC X», а процесс: декомпозиция, EDA, выбор модели, валидация, разговор о переобучении.
Решение
Шаг 1. Понять задачу и метрику
- Что значит
target=1бизнес-вижн? (например, «откликнулся на предложение» / «дефолт»). От ответа зависит, что считать ошибкой первого/второго рода. - Сбалансирован ли таргет? Если редкий — accuracy бесполезна, нужны ROC-AUC, PR-AUC, recall@k.
- Стоимость FP/FN. Скоринг на дорогой продукт — recall важнее; антифрод — precision.
В отсутствие подробностей берём как baseline ROC-AUC + F1 на пороге 0.5, потом обсуждаем оптимальный порог.
Шаг 2. EDA
import pandas as pd
df = pd.read_excel("data.xlsx", sheet_name="Задача1")
print(df.shape, df.dtypes)
print(df.target.value_counts(normalize=True))
print(df.describe(include="all"))
print(df.isna().mean().sort_values(ascending=False))Что искать:
- Доля
target=1. Если 1–5% — классовый дисбаланс, нужны class_weight / SMOTE / specialized loss. - Распределения:
PROFIT_FAMILY,DCI,UCIмогут иметь длинные хвосты и нули — обычно нужна логарифм-трансформация. - Категориальные булевы: проверить связь с target через
groupby(col).target.mean()— это уже даёт прокси-силу признака. - Утечки:
ID— не признак (выбросить).
Шаг 3. Препроцессинг и валидация
Разбиваем данные до любого fit, чтобы не подсунуть тесту знания о трейне:
from sklearn.model_selection import StratifiedKFold, train_test_split
X = df.drop(columns=["ID", "target"])
y = df["target"]
X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.2, stratify=y, random_state=42)
cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)Преобразования (в Pipeline, чтобы fit-ить только на train):
- бинарные оставляем как есть;
EDUCATION→ one-hot или target encoding (с CV-фолдами, иначе утечка);- числовые: лог + стандартизация для линейных моделей; для деревьев — без преобразований.
Шаг 4. Выбор модели
Сравниваем три кандидата (по возрастанию сложности):
| Модель | Плюсы | Минусы |
|---|---|---|
| Logistic Regression | Интерпретируема, быстра, baseline | Нелинейности захватывает только через feature engineering |
| Random Forest | Нелинейности, устойчив к шуму | Хуже калибровка вероятностей |
| Gradient Boosting (LightGBM/CatBoost) | Лучшее качество на табличке | Риск переобучения, нужна настройка |
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
import lightgbm as lgb
from sklearn.metrics import roc_auc_score
from sklearn.model_selection import cross_val_score
models = {
"logreg": LogisticRegression(max_iter=2000, class_weight="balanced"),
"rf": RandomForestClassifier(n_estimators=500, class_weight="balanced", n_jobs=-1, random_state=42),
"lgb": lgb.LGBMClassifier(n_estimators=500, learning_rate=0.05, num_leaves=31, random_state=42),
}
for name, m in models.items():
auc = cross_val_score(m, X_tr_prep, y_tr, scoring="roc_auc", cv=cv, n_jobs=-1).mean()
print(name, round(auc, 4))Решение принимаем по CV-AUC, не по trainscore.
Шаг 5. Стабильность и переобучение
«Стабилен ли прогноз?» — три проверки:
- CV vs holdout. Если AUC на 5-fold CV ≈ AUC на отложенном тесте — модель стабильна. Большая разница (0.85 на CV, 0.72 на тесте) = переобучение.
- Шум в фолдах. Стандартное отклонение AUC между фолдами. Если
mean=0.80, std=0.04— нестабильно. - Bootstrap CI. Реземплируем тест и считаем 95% CI на AUC. Узкий — стабильно.
Признаки переобучения:
- AUC на train сильно выше, чем на test/CV (у бустинга — типично, лечится
min_data_in_leaf, ранней остановкой, регуляризацией). - Малое число наблюдений по сравнению с числом признаков: при и 13 фичах LightGBM с дефолтами выучит шум. Имеет смысл отдать предпочтение logreg / небольшому RF.
Шаг 6. Интерпретация
- LogReg: коэффициенты после стандартизации = «вклад» в логиты.
- Tree-based:
feature_importances_или SHAP для глобальной/локальной интерпретации. - Разговор «почему именно эта модель» строим вокруг трёх осей: качество, стабильность, интерпретируемость для бизнеса.
Подводные камни
- Утечки.
ID, дата создания, агрегаты, считающиеся «по будущему». Всегда проверяйте, что фичи доступны на момент предсказания. - Дисбаланс классов. Не оценивайте по accuracy. Сразу AUC + PR-AUC + матрица ошибок на оптимальном пороге.
- Категориальные с малой кардинальностью + target encoding на одном фолде. Вызывает оптимистическое смещение CV. Используйте
category_encoders.TargetEncoderвнутриPipelineили out-of-fold. - Маленькая выборка. При предпочтительнее простые модели и регуляризация. CV — обязательно стратифицированный.
- Один тест-сплит → false confidence. На малой выборке одно разбиение не показатель. Делайте повторяемый k-fold + bootstrap CI.
- «Запомнил ID». Если в фичи попадает
IDили сильный квази-айди (вродеSIML, который коррелирует с порядковой записью), модель «запомнит» обучение и не обобщится.
Эталонный ответ (структура)
- Метрика: ROC-AUC + F1, обоснование по бизнесу.
- EDA: распределения, пропуски, дисбаланс target.
- Pipeline: препроцессинг (log + стандартизация для линейных, OHE для
EDUCATION). - Модели: LogReg → RF → LightGBM, выбор по 5-fold CV-AUC.
- Стабильность: CV vs holdout, std AUC по фолдам, bootstrap CI.
- Защита от переобучения: ранняя остановка, регуляризация, ограничение глубины, контроль train/test gap.
- Интерпретация: SHAP / коэффициенты, бизнес-вывод.
Главное на собесе — проговорить процесс и риски. Конкретное число AUC второстепенно.