Условие
У модели train AUC = 0.99, test AUC = 0.72. Это переобучение? Какими способами диагностировать и какими бороться?
Решение
Диагностика — да, это сильное переобучение
Разрыв train vs val/test > 5-10 п.п. — обычно переобучение. AUC 0.27 разница — катастрофическая.
Дополнительные проверки
1. Learning curves
from sklearn.model_selection import learning_curve
import matplotlib.pyplot as plt
import numpy as np
sizes, tr, va = learning_curve(model, X, y, cv=5, scoring='roc_auc',
train_sizes=np.linspace(0.1, 1.0, 8))
plt.plot(sizes, tr.mean(axis=1), label='train')
plt.plot(sizes, va.mean(axis=1), label='val')
plt.fill_between(sizes, va.mean(1)-va.std(1), va.mean(1)+va.std(1), alpha=0.2)
plt.legend(); plt.xlabel('Train size'); plt.ylabel('AUC')Признаки переобучения:
- train ≫ val при всех sizes.
- val не растёт с n_train — модель не учится из доп. данных.
2. Validation curve по гиперпараметру
from sklearn.model_selection import validation_curve
depths = range(2, 15)
tr, va = validation_curve(model, X, y, 'max_depth', depths, cv=5, scoring='roc_auc')U-образная val curve → есть «правильная» сложность.
3. CV stability
from sklearn.model_selection import cross_val_score
scores = cross_val_score(model, X, y, cv=10, scoring='roc_auc')
print(f"AUC: {scores.mean():.3f} ± {scores.std():.3f}")Высокая std (>0.05) — нестабильно, видимо переобучение или leakage.
4. Leakage-чеклист
- Фича вычислена с использованием target?
- Train/test разделение учитывает группировку?
- Препроцессинг (Scaler/Encoder) fit на full data?
- Временной leakage (фича из будущего)?
Способы бороться
1. Регуляризация:
- LightGBM / XGBoost:
min_child_samples,reg_alpha,reg_lambda,feature_fraction,bagging_fraction. - Логрег: L1/L2.
- NN: dropout, weight decay.
2. Уменьшить ёмкость модели:
max_depth: 6-8 для деревьев бустинга.n_estimators: оставить только до early stopping.- Меньше слоёв / нейронов в NN.
3. Больше данных:
- Собрать ещё.
- Augmentation для картинок / текстов.
4. Feature selection:
- 500 фич с одним полезным сигналом → переобучение. Убрать лишние.
5. Early stopping:
import lightgbm as lgb
model = lgb.LGBMClassifier(n_estimators=1000)
model.fit(X_tr, y_tr,
eval_set=[(X_val, y_val)],
callbacks=[lgb.early_stopping(50)])Прекращает обучение, когда val перестаёт улучшаться.
6. Ensemble:
- Bagging (Random Forest) уменьшает variance.
- Stacking → ровнее ошибки.
7. CV для подбора гиперов:
- Не подбирать на test (это уже не test!).
- Использовать nested CV для honest estimate.
Specifically для AUC 0.99 vs 0.72
Подозрения:
- Leakage — самое вероятное. Что-то с target прокралось в фичи (например,
target_lag1илиcohort_avg_y_other_usersбез OOF). - Слишком сложная модель: depth=20, n_estimators=2000, без regularization.
- Малая выборка: на 1000 строк и 200 фичах любой XGBoost переобучится.
- Stratification сломана: классы перетекли в train.
Проверить в первую очередь — feature_importance и SHAP: какая фича доминирует с подозрительной силой?
imp = pd.Series(model.feature_importances_, index=X.columns).sort_values(ascending=False)
print(imp.head(10))
# если одна фича > 50% importance — почти всегда leakageSanity check: пермутация target
Если перемешать target и AUC всё равно 0.7 — это не leakage, а baseline-эффект от структуры данных:
np.random.shuffle(y_train)
model.fit(X_train, y_train)
# val AUC должен быть ≈ 0.5; если выше — leakage в splitПодводные камни
- Train высокий, test нормальный — не всегда плохо: deep models часто доводят train до 1.0, но это ок, если test = бизнес-target.
- Test AUC 0.72 мог бы быть нормальным для задачи — переобучение определяется по разнице, не по абсолюту.
- CV-AUC 0.99 — почти всегда leakage; реальные задачи редко имеют AUC > 0.95.
early_stoppingна test set = leakage. Только на отдельный val.- Регуляризация без CV — гадание; всегда подбирать.
- «Бороться с переобучением» не нужно, если train ≈ val. Не «лечите здоровое».
Эталонный ответ
Да, переобучение (AUC 0.99 vs 0.72 — разрыв 27 п.п.).
Диагностика:
- Learning curves: train ≫ val при всех sizes;
- Validation curve по depth/n_estimators;
- CV stability (std > 0.05 → проблема);
- Leakage-чеклист (фича из будущего, target в фичах, общий fit);
- Sanity-check через permuted y.
Борьба:
- Регуляризация (
reg_alpha,reg_lambda,min_child_samples); - Уменьшить depth / n_estimators (+ early_stopping);
- Снять подозрительно «информативные» фичи (leakage candidates);
- Больше данных / augmentation;
- Bagging / ensemble.
Первая гипотеза при AUC 0.99 на train — leakage, а не «слишком сложная модель».