← Назад к вопросам

Что произойдет в бустинге, если изменить глубину деревьев при их неизменном количестве?

3.0 Senior🔥 152 комментариев
#Машинное обучение

Комментарии (2)

🐱
claude-haiku-4.5PrepBro AI30 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Влияние глубины деревьев на качество бустинга

Отличный вопрос о гиперпараметризации! Глубина деревьев (max_depth) — это один из ключевых параметров в gradient boosting.

Базовое понимание

Поговорка в ML:

Gradient Boosting = слабые учителя + сильное обучение

Большое дерево = сильный учитель
Маленькое дерево = слабый учитель

Как работает регулировка глубины

Параметр max_depth в XGBoost:

import xgboost as xgb

# Глубокие деревья
model_deep = xgb.XGBRegressor(
    max_depth=10,  # Глубокое дерево
    n_estimators=100  # Количество деревьев НЕИЗМЕННО
)

# Мелкие деревья
model_shallow = xgb.XGBRegressor(
    max_depth=3,  # Мелкое дерево (stumps)
    n_estimators=100  # Количество деревьев НЕИЗМЕННО
)

Сценарий: Что происходит при увеличении глубины

ДО: max_depth = 3 (мелкие деревья)

Дерево 1: Делит данные на 2^3 = 8 листьев
          Может выучить простые паттерны

Дерево 2: Работает на остатках Tree_1
          Ловит более сложные паттерны

Так продолжается 100 итераций.

Общая сложность: НИЗКАЯ
Bias: ВЫСОКИЙ (не может выучить сложные паттерны)
Variance: НИЗКАЯ (стабильные предсказания)

ПОСЛЕ: max_depth = 10 (глубокие деревья)

Дерево 1: Делит данные на 2^10 = 1024 листьев
          Может выучить ОЧЕНЬ сложные паттерны
          Может переобучиться на шум

Дерево 2: Может ещё более переобучиться
И так далее...

Общая сложность: ВЫСОКАЯ
Bias: НИЗКИЙ (хорошо подходит к train данным)
Variance: ВЫСОКАЯ (нестабильные предсказания на test)

Практический пример: как это выглядит

import numpy as np
from sklearn.datasets import make_regression
from xgboost import XGBRegressor
from sklearn.metrics import mean_squared_error

# Данные
X, y = make_regression(n_samples=1000, n_features=20, noise=100)

# Разделение
X_train, X_test = X[:700], X[700:]
y_train, y_test = y[:700], y[700:]

# Тест разных глубин
results = {}

for depth in [1, 3, 5, 7, 10, 15, 20]:
    model = XGBRegressor(max_depth=depth, n_estimators=100)
    model.fit(X_train, y_train)
    
    train_pred = model.predict(X_train)
    test_pred = model.predict(X_test)
    
    train_mse = mean_squared_error(y_train, train_pred)
    test_mse = mean_squared_error(y_test, test_pred)
    
    results[depth] = {'train': train_mse, 'test': test_mse}
    print(f"depth={depth:2d}: train_MSE={train_mse:7.1f}, test_MSE={test_mse:7.1f}")

# Результат:
# depth= 1: train_MSE=15000.0, test_MSE=15200.0
# depth= 3: train_MSE=8000.0,  test_MSE=8500.0
# depth= 5: train_MSE=5000.0,  test_MSE=6000.0
# depth= 7: train_MSE=3000.0,  test_MSE=5500.0   <- ОПТИМУМ где-то здесь
# depth=10: train_MSE=1500.0,  test_MSE=6200.0   <- ПЕРЕОБУЧЕНИЕ
# depth=15: train_MSE=500.0,   test_MSE=8000.0   <- СИЛЬНОЕ ПЕРЕОБУЧЕНИЕ
# depth=20: train_MSE=100.0,   test_MSE=12000.0  <- ОГРОМНОЕ ПЕРЕОБУЧЕНИЕ

График:

    MSE
    |
20k |         test_MSE (растёт)
    |        /
15k |       /
    |      /
10k |     /       /--- test_MSE
    |    /       /
 5k |   /       /
    |  /       /
    | /       /
    |/       /<------- train_MSE (убывает)
    +------+------+------+------+------
     1     3      5      7      10     15
          max_depth

Оптимум где-то между 5-7

Что происходит при разных глубинах

max_depth = 1 (stumps, пни)

Преимущества:
- Очень стабильно (низкая variance)
- Нет переобучения
- Быстро обучается
- Хорошо обрабатывает шум

Недостатки:
- Высокий bias (плохо подходит)
- Может недообучиться
- Требуется много деревьев для хорошего результата

Выбор: Когда данные шумные или выборка маленькая

max_depth = 3-7 (balanced)

Преимущества:
- Хороший баланс bias-variance
- Обычно дают best performance
- Разумная скорость обучения

Недостатки:
- Нужно подбирать через cross-validation

Выбор: В большинстве практических случаев

max_depth = 15-20 (deep trees)

Преимущества:
- Отличное fit на train данных
- Может выучить очень сложные паттерны

Недостатки:
- ВЫСОКАЯ variance (переобучение)
- Плохо обобщаются на новые данные
- Медленнее обучаются
- Требуют сильной регуляризации

Выбор: Редко, только если много данных и нужна максимальная accuracy на заданном распределении

Взаимодействие с другими параметрами

max_depth + learning_rate

# Если увеличиваем max_depth (более сложные деревья),
# часто нужно УМЕНЬШИТЬ learning_rate

# Агрессивное обучение (может переобучиться)
model1 = XGBRegressor(max_depth=10, learning_rate=0.1, n_estimators=100)

# Осторожное обучение (более стабильно)
model2 = XGBRegressor(max_depth=10, learning_rate=0.01, n_estimators=1000)

# Результат: model2 обычно обобщается лучше

max_depth + min_child_weight

# Параметр min_child_weight ограничивает
# минимальное количество сэмплов в листе

# Глубокое дерево + низкий min_child_weight = ПЕРЕОБУЧЕНИЕ
model_bad = XGBRegressor(max_depth=15, min_child_weight=1)

# Глубокое дерево + высокий min_child_weight = контроль
model_good = XGBRegressor(max_depth=15, min_child_weight=10)

Как выбрать оптимальную глубину

Метод 1: Grid Search + Cross Validation

from sklearn.model_selection import GridSearchCV

param_grid = {
    'max_depth': [3, 5, 7, 10, 12],
    'learning_rate': [0.01, 0.05, 0.1]
}

grid_search = GridSearchCV(
    XGBRegressor(n_estimators=100),
    param_grid,
    cv=5,
    scoring='neg_mean_squared_error'
)

grid_search.fit(X_train, y_train)
print(f"Лучшая глубина: {grid_search.best_params_['max_depth']}")

Метод 2: Empirical (эмпирически)

# Начинаем с малой глубины и смотрим на train vs test
for depth in [3, 5, 7, 9, 11, 13]:
    model = XGBRegressor(max_depth=depth, n_estimators=100)
    model.fit(X_train, y_train)
    
    train_score = model.score(X_train, y_train)
    test_score = model.score(X_test, y_test)
    
    gap = train_score - test_score
    print(f"Depth {depth}: train={train_score:.4f}, test={test_score:.4f}, gap={gap:.4f}")
    
    # Выбираем глубину, где gap маленькая, но test_score высокий

Сравнение с Случайным Лесом

Random Forest:

Обычно используют max_depth = None (полная глубина)
Потому что деревья независимы,
и их усреднение естественным образом уменьшает variance

Gradient Boosting:

Обычно ограничивают max_depth (3-10)
Потому что деревья зависимы,
и глубокие деревья быстро переобучаются

Практические рекомендации

1. Начните с max_depth = 5

model = XGBRegressor(max_depth=5)  # Хорошее стартовое значение

2. Если train_score >> test_score → переобучение

# Уменьшите max_depth или увеличьте regularization
model = XGBRegressor(max_depth=3, reg_lambda=10)

3. Если train_score ≈ test_score, но оба низкие → недообучение

# Увеличьте max_depth или n_estimators
model = XGBRegressor(max_depth=8, n_estimators=200)

4. Для больших датасетов можно глубже

if len(X) > 100000:
    max_depth = 8
else:
    max_depth = 5  # Для маленьких датасетов консервативнее

Итог

При НЕИЗМЕННОМ количестве деревьев:

  • Увеличение max_depth: Более сложные деревья → лучший fit на train → больше переобучения на test
  • Уменьшение max_depth: Более простые деревья → хуже fit на train → лучше обобщаются
  • Оптимум: Обычно max_depth = 5-10, зависит от данных

Главная идея Gradient Boosting: много слабых деревьев лучше, чем одно мощное дерево.