← Назад к вопросам
Как регуляризуется бустинг?
2.3 Middle🔥 122 комментариев
#Машинное обучение#Статистика и A/B тестирование
Комментарии (2)
🐱
claude-haiku-4.5PrepBro AI29 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Как регуляризуется бустинг?
Бустинг (Boosting) — один из самых мощных методов машинного обучения, но он легко переобучается. Регуляризация в бустинге критична для хорошего обобщения. Давайте разберёмся в основных техниках.
1. Теория: почему бустинг нуждается в регуляризации?
print("=== Проблемы переобучения в бустинге ===")
print("\n1. ПОСЛЕДОВАТЕЛЬНОЕ УЛУЧШЕНИЕ ОШИБОК")
print(" Каждый следующий learner фокусируется на предыдущих ошибках")
print(" Может привести к переподстройке под шум")
print("\n2. СЛОЖНОСТЬ АНСАМБЛЯ")
print(" Добавляем всё больше моделей")
print(" Без регуляризации = переобучение")
print("\n3. АДАПТАЦИЯ К ШУМУ")
print(" На поздних итерациях модель может адаптироваться только к шуму")
print(" Качество на новых данных падает")
2. Основной механизм регуляризации: Learning Rate
import numpy as np
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.metrics import roc_auc_score
import matplotlib.pyplot as plt
X, y = make_classification(n_samples=5000, n_features=20, n_informative=10, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# Learning rate (также называется shrinkage или eta) — самая важная регуляризация
print("=== Learning Rate (Shrinkage) ===")
print("\nФормула обновления:")
print("y_pred_new = y_pred_old + learning_rate * tree_contribution")
print("\nДействие:")
print("- learning_rate = 1.0: используем полный вклад каждого дерева")
print("- learning_rate = 0.1: используем 10% вклада каждого дерева")
print("- learning_rate = 0.01: используем 1% вклада каждого дерева")
print("\nЭффект:")
print("- Большая learning_rate -> быстрое обучение, высокий риск переобучения")
print("- Малая learning_rate -> медленное обучение, лучшее обобщение")
print("- Нужно больше итераций при малой learning_rate")
# Практический пример
learning_rates = [0.001, 0.01, 0.05, 0.1, 0.2, 0.5, 1.0]
train_scores = []
test_scores = []
for lr in learning_rates:
model = GradientBoostingClassifier(
n_estimators=500, # много итераций
learning_rate=lr, # регуляризация
max_depth=5,
random_state=42
)
model.fit(X_train, y_train)
train_auc = roc_auc_score(y_train, model.predict_proba(X_train)[:, 1])
test_auc = roc_auc_score(y_test, model.predict_proba(X_test)[:, 1])
train_scores.append(train_auc)
test_scores.append(test_auc)
print(f"LR={lr:5.3f}: Train AUC={train_auc:.4f}, Test AUC={test_auc:.4f}, Gap={train_auc-test_auc:.4f}")
# Визуализируем
plt.figure(figsize=(10, 6))
plt.semilogx(learning_rates, train_scores, 'o-', linewidth=2, label='Train AUC')
plt.semilogx(learning_rates, test_scores, 's-', linewidth=2, label='Test AUC')
plt.xlabel('Learning Rate')
plt.ylabel('AUC')
plt.title('Effect of Learning Rate on Boosting')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
3. Остановка по ошибке валидации (Early Stopping)
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.model_selection import train_test_split
print("=== Early Stopping ===")
print("\nИдея:")
print("1. Разделяем train на train и validation")
print("2. После каждой итерации проверяем ошибку на validation")
print("3. Если ошибка растёт -> СТОП, не учимся дальше")
print("4. Берём лучшую модель")
# Разделяем train на train и validation
X_tr, X_val, y_tr, y_val = train_test_split(X_train, y_train, test_size=0.2, random_state=42)
# Обучаем с early stopping
model = GradientBoostingClassifier(
n_estimators=1000,
learning_rate=0.05,
max_depth=5,
random_state=42,
validation_fraction=0.2, # 20% для валидации
n_iter_no_change=50, # стоп если 50 итераций без улучшения
tol=1e-4 # минимальное улучшение
)
model.fit(X_train, y_train)
print(f"\nЛучшее количество итераций: {model.n_estimators_}")
print(f"Мы бы обучали 1000, но остановились на {model.n_estimators_}")
# Метрики
train_auc = roc_auc_score(y_train, model.predict_proba(X_train)[:, 1])
test_auc = roc_auc_score(y_test, model.predict_proba(X_test)[:, 1])
print(f"\nTrain AUC: {train_auc:.4f}")
print(f"Test AUC: {test_auc:.4f}")
print(f"Overfitting gap: {train_auc - test_auc:.4f}")
4. Глубина деревьев (Tree Depth)
print("=== Ограничение глубины деревьев ===")
print("\nВеак learners vs Strong learners:")
print("- Weak learners: max_depth = 1-3 (пни и малые деревья)")
print("- Strong learners: max_depth = 5-10 (более сложные деревья)")
print("\nДействие max_depth:")
print("- Меньше глубина -> меньше каждого дерева способно переобучиться")
print("- Нужно больше деревьев для хорошего результата")
print("- Но ансамбль в целом более стабилен")
# Пример
max_depths = [1, 2, 3, 5, 8, 10, 15]
for max_d in max_depths:
model = GradientBoostingClassifier(
n_estimators=200,
learning_rate=0.1,
max_depth=max_d,
random_state=42
)
model.fit(X_train, y_train)
train_auc = roc_auc_score(y_train, model.predict_proba(X_train)[:, 1])
test_auc = roc_auc_score(y_test, model.predict_proba(X_test)[:, 1])
print(f"max_depth={max_d:2d}: Train={train_auc:.4f}, Test={test_auc:.4f}, Gap={train_auc-test_auc:.4f}")
5. Минимум примеров в листе (min_samples_leaf)
print("=== min_samples_leaf и min_samples_split ===")
print("\nСмысл:")
print("min_samples_leaf: каждый лист содержит минимум N примеров")
print("min_samples_split: разбиение возможно только если >= N примеров")
print("\nРегуляризация:")
print("- Больше min_samples -> проще деревья")
print("- Проще деревья -> меньше дисперсия")
print("- Выше смещение, но лучше обобщение")
model_good = GradientBoostingClassifier(
n_estimators=200,
learning_rate=0.05,
max_depth=5,
min_samples_leaf=10, # каждый лист >= 10 примеров
min_samples_split=20, # разбиение при >= 20 примеров
subsample=0.8, # (см ниже)
random_state=42
)
model_good.fit(X_train, y_train)
6. Subsampling (выборка строк)
print("=== Subsample (Stochastic Gradient Boosting) ===")
print("\nИдея:")
print("Вместо того чтобы обучать каждое дерево на ВСЕх примерах,")
print("обучаем на случайной подвыборке (например, 80%)")
print("\nДействие:")
print("- subsample=1.0: используем все примеры (обычный GBM)")
print("- subsample=0.8: используем 80% случайных примеров")
print("- subsample=0.5: используем 50% случайных примеров")
print("\nЭффект регуляризации:")
print("1. Добавляет случайность -> разные деревья")
print("2. Меньше примеров -> невозможно запомнить детали")
print("3. Похоже на Bagging -> уменьшает дисперсию")
subsamples = [0.5, 0.7, 0.8, 0.9, 1.0]
for subsamp in subsamples:
model = GradientBoostingClassifier(
n_estimators=200,
learning_rate=0.1,
max_depth=5,
subsample=subsamp,
random_state=42
)
model.fit(X_train, y_train)
train_auc = roc_auc_score(y_train, model.predict_proba(X_train)[:, 1])
test_auc = roc_auc_score(y_test, model.predict_proba(X_test)[:, 1])
print(f"subsample={subsamp:.1f}: Train={train_auc:.4f}, Test={test_auc:.4f}")
7. Feature Subsampling (выборка признаков)
print("=== Feature Subsampling (max_features) ===")
print("\nПараметры:")
print("max_features='sqrt': используем sqrt(n) случайных признаков")
print("max_features='log2': используем log2(n) случайных признаков")
print("max_features=0.8: используем 80% случайных признаков")
print("max_features=None: используем ВСЕ признаки")
print("\nДействие регуляризации:")
print("1. Меньше признаков -> проще деревья")
print("2. Добавляет случайность -> разнообразие")
print("3. Каждое дерево знает меньше -> не может запомнить")
model = GradientBoostingClassifier(
n_estimators=200,
learning_rate=0.1,
max_depth=5,
max_features='sqrt', # регуляризация по признакам
random_state=42
)
model.fit(X_train, y_train)
8. Регуляризация в XGBoost: параметры
from xgboost import XGBClassifier
print("=== Регуляризация в XGBoost ===")
# XGBoost имеет встроенные параметры регуляризации
model_xgb = XGBClassifier(
# Похоже на GradientBoosting
n_estimators=200,
learning_rate=0.05, # eta (learning rate)
max_depth=5,
subsample=0.8, # выборка строк
colsample_bytree=0.8, # выборка признаков для каждого дерева
colsample_bylevel=0.8, # выборка признаков для каждого уровня
colsample_bynode=0.8, # выборка признаков для каждого узла
# Специфично для XGBoost
min_child_weight=1, # минимальная сумма весов в листе
gamma=0, # минимальное улучшение для разделения
reg_alpha=0, # L1 регуляризация
reg_lambda=1, # L2 регуляризация
random_state=42
)
model_xgb.fit(X_train, y_train)
print("\nКлючевые параметры XGBoost:")
print("- learning_rate: 0.01-0.1 (меньше = консервативнее)")
print("- max_depth: 3-8 (меньше = проще)")
print("- subsample: 0.5-1.0 (меньше = больше регуляризация)")
print("- colsample_bytree: 0.5-1.0 (меньше = больше регуляризация)")
print("- gamma: 0-5 (больше = меньше разделений)")
print("- reg_alpha (L1), reg_lambda (L2): 0-10 (больше = сильнее штраф)")
9. Комплексная регуляризация
print("=== Оптимальная конфигурация GBM ===")
# Для среднего датасета (1000-10000 примеров)
model_optimal = GradientBoostingClassifier(
# Основные параметры
n_estimators=500, # много итераций
learning_rate=0.05, # консервативный learning rate
# Регуляризация структуры деревьев
max_depth=5, # глубина
min_samples_split=20, # минимум для разбиения
min_samples_leaf=10, # минимум в листе
max_features='sqrt', # выборка признаков
# Регуляризация через выборку
subsample=0.8, # выборка строк
# Early stopping
validation_fraction=0.2,
n_iter_no_change=50,
tol=1e-4,
random_state=42
)
model_optimal.fit(X_train, y_train)
train_auc = roc_auc_score(y_train, model_optimal.predict_proba(X_train)[:, 1])
test_auc = roc_auc_score(y_test, model_optimal.predict_proba(X_test)[:, 1])
print(f"\nOptimal GBM:")
print(f"Train AUC: {train_auc:.4f}")
print(f"Test AUC: {test_auc:.4f}")
print(f"Overfitting gap: {train_auc - test_auc:.4f}")
10. Рекомендации
print("=== Стратегия регуляризации бустинга ===")
print("\nШаг 1: Learning Rate")
print(" - Выбери low learning_rate (0.01-0.1)")
print(" - Это позволит обучаться медленнее и стабильнее")
print(" - n_estimators должен быть большим (200-1000)")
print("\nШаг 2: Tree Depth")
print(" - Начни с max_depth=3-5")
print(" - Это weak learners")
print(" - Они не переобучаются сильно")
print("\nШаг 3: Early Stopping")
print(" - Установи validation_fraction и n_iter_no_change")
print(" - Это предотвратит обучение слишком долго")
print("\nШаг 4: Subsampling")
print(" - subsample=0.7-0.8")
print(" - colsample_bytree=0.7-0.8")
print(" - Это добавляет случайность")
print("\nШаг 5: Cross-validation & Tuning")
print(" - Используй GridSearch или RandomSearch")
print(" - Оптимизируй по CV метрике")
print(" - Не на train, не на test")
Ключевые выводы
- Learning Rate — самый важный параметр регуляризации
- Early Stopping — прекращаем обучение когда качество падает
- Tree Depth — ограничиваем сложность каждого дерева
- Subsampling (строк и признаков) добавляет разнообразие
- min_samples_leaf & min_samples_split делают деревья проще
- XGBoost имеет встроенные L1/L2 параметры
- Комбинация техник — используй несколько одновременно
- Cross-validation — проверяй всегда на независимых данных