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

Как работает gradient-boosting регрессор?

1.0 Junior🔥 191 комментариев
#Машинное обучение

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

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

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

Как работает gradient-boosting регрессор?

Gradient Boosting — один из самых мощных алгоритмов машинного обучения для регрессии. Основная идея: последовательно строим слабые модели (обычно деревья решений) так, чтобы каждая новая модель улучшала ошибки предыдущих.

Основная идея

Вместо одного мощного дерева (которое переобучается), строим много слабых деревьев, каждое из которых прогнозирует остаток (residual) предыдущего дерева.

Шаг 0: F₀(x) = среднее значение y (базовое предсказание)
Шаг 1: residual₁ = y - F₀(x)
        F₁(x) = F₀(x) + tree₁(x)  // tree₁ прогнозирует residual₁

Шаг 2: residual₂ = y - F₁(x)
        F₂(x) = F₁(x) + tree₂(x)  // tree₂ прогнозирует residual₂
        
...

Финаль: F_final(x) = F₀(x) + α*tree₁(x) + α*tree₂(x) + ... + α*tree_n(x)
        α = learning_rate (обычно 0.01-0.1)

Математическое описание

Функция потерь

Для регрессии обычно используем Mean Squared Error (MSE):

L = (1/n) * Σ(y_i - ŷ_i)²

Напомни о градиентном спуске:

∂L/∂y_pred = -2(y - ŷ)  // градиент ошибки

Идея gradient boosting: используем градиент, чтобы понять, куда направить следующее дерево!

Пошаговый алгоритм

1. Инициализировать F₀(x) = mean(y)  // начальное предсказание

2. ДЛЯ каждого шага m = 1 до M:
   a) Вычислить градиент: g_i = -∂L/∂ŷ|ŷ=F_{m-1}(x_i)
      Для MSE: g_i = y_i - F_{m-1}(x_i)  // просто остатки!
   
   b) Обучить дерево h_m(x) предсказывать градиенты g_i
   
   c) Найти optimal learning rate:
      γ_m = argmin_γ Σ L(y_i, F_{m-1}(x_i) + γ*h_m(x_i))
   
   d) Обновить модель:
      F_m(x) = F_{m-1}(x) + learning_rate * h_m(x)

Пример: пошагово от нуля

import numpy as np
import pandas as pd
from sklearn.tree import DecisionTreeRegressor
from sklearn.metrics import mean_squared_error

def gradient_boosting_regressor(X_train, y_train, n_estimators=100, 
                               learning_rate=0.1, max_depth=3):
    """
    Простая реализация Gradient Boosting Regressor с нуля
    """
    
    trees = []
    predictions = np.zeros(len(X_train))
    
    # Шаг 1: Инициализируем базовое предсказание (среднее)
    base_prediction = np.mean(y_train)
    predictions = np.full(len(X_train), base_prediction)
    
    # Шаг 2: Строим последовательность деревьев
    for i in range(n_estimators):
        # Вычислить остаток (градиент для MSE)
        residuals = y_train - predictions
        
        # Обучить дерево на остатках
        tree = DecisionTreeRegressor(
            max_depth=max_depth,
            min_samples_leaf=1,
            random_state=42
        )
        tree.fit(X_train, residuals)
        trees.append(tree)
        
        # Обновить предсказания
        tree_predictions = tree.predict(X_train)
        predictions += learning_rate * tree_predictions
        
        # Логирование
        mse = mean_squared_error(y_train, predictions)
        if (i + 1) % 10 == 0:
            print(f"Iteration {i+1}, MSE: {mse:.4f}")
    
    return base_prediction, trees

def predict_gb(X_test, base_pred, trees, learning_rate=0.1):
    """Предсказание с построенной GB моделью"""
    predictions = np.full(len(X_test), base_pred)
    
    for tree in trees:
        tree_pred = tree.predict(X_test)
        predictions += learning_rate * tree_pred
    
    return predictions

# Использование
from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split

X, y = make_regression(n_samples=200, n_features=10, noise=10, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

base_pred, trees = gradient_boosting_regressor(X_train, y_train, 
                                              n_estimators=50, 
                                              learning_rate=0.1)

y_pred = predict_gb(X_test, base_pred, trees, learning_rate=0.1)
print(f"Test MSE: {mean_squared_error(y_test, y_pred):.4f}")

Visualизация процесса

Итерация 1:
──────────
Остаток:    ┃     y - pred
            ┃  ╱╲
            ┃ ╱  ╲
            ┗━━━━━━
            
Дерево 1 learns это → new pred = pred + tree₁

Итерация 2:
──────────
Новый остаток:  ┃    y - (pred + tree₁)
                ┃     │
                ┃    ╱╲  ← меньше ошибка!
                ┃   ╱  ╲
                ┗━━━━━━

Дерево 2 learns это → new pred = pred + tree₁ + tree₂

... процесс повторяется, ошибка медленно уменьшается

Различные функции потерь

MSE (Mean Squared Error) — стандартная для регрессии:

class MSELoss:
    def gradient(self, y_true, y_pred):
        return y_true - y_pred  # для MSE просто разница!
    
    def hessian(self, y_true, y_pred):
        return np.ones_like(y_pred)  # для Newton step

MAE (Mean Absolute Error) — более robust к выбросам:

class MAELoss:
    def gradient(self, y_true, y_pred):
        return np.sign(y_true - y_pred)

Huber Loss — комбинация MSE и MAE:

class HuberLoss:
    def __init__(self, delta=1.0):
        self.delta = delta
    
    def gradient(self, y_true, y_pred):
        diff = y_true - y_pred
        if abs(diff) <= self.delta:
            return diff
        else:
            return self.delta * np.sign(diff)

Практическое использование (sklearn / XGBoost)

Scikit-learn GradientBoostingRegressor

from sklearn.ensemble import GradientBoostingRegressor
from sklearn.metrics import mean_squared_error, r2_score

model = GradientBoostingRegressor(
    n_estimators=200,           # количество деревьев
    learning_rate=0.1,          # размер шага (0.01-0.3)
    max_depth=5,                # глубина каждого дерева
    min_samples_split=5,        # минимум сэмплов для расщепления
    min_samples_leaf=2,         # минимум сэмплов в листе
    subsample=0.8,              # fraction of samples for each tree (Stochastic GB)
    loss='squared_error',       # 'squared_error', 'absolute_error', 'huber'
    random_state=42,
    n_jobs=-1
)

model.fit(X_train, y_train)
y_pred = model.predict(X_test)

print(f"R²: {r2_score(y_test, y_pred):.4f}")
print(f"RMSE: {np.sqrt(mean_squared_error(y_test, y_pred)):.4f}")

# Feature importance
importances = model.feature_importances_
for feat, imp in sorted(zip(feature_names, importances), 
                       key=lambda x: x[1], reverse=True)[:5]:
    print(f"{feat}: {imp:.4f}")

XGBoost Regressor

import xgboost as xgb

model = xgb.XGBRegressor(
    n_estimators=200,
    learning_rate=0.1,
    max_depth=5,
    min_child_weight=1,
    subsample=0.8,
    colsample_bytree=0.8,
    objective='reg:squarederror',  # 'reg:squarederror', 'reg:pseudohubererror'
    random_state=42,
    n_jobs=-1
)

model.fit(
    X_train, y_train,
    eval_set=[(X_test, y_test)],
    early_stopping_rounds=20,
    verbose=False
)

y_pred = model.predict(X_test)
print(f"Test RMSE: {np.sqrt(mean_squared_error(y_test, y_pred)):.4f}")

Почему это работает так хорошо?

1. Последовательность улучшает: каждое новое дерево исправляет
   ошибки предыдущих → очень эффективно

2. Использует градиенты: направляет поиск в сторону минимума функции
   потерь (как обычный gradient descent, но с деревьями)

3. Regulization:
   - learning_rate: меньше шаг → медленнее, но стабильнее
   - max_depth: неглубокие деревья → слабые базовые модели
   - subsample: случайный сэмплинг → меньше переобучение

4. Гибкость: можем использовать разные loss functions для разных задач

Сравнение с Random Forest

АспектGradient BoostingRandom Forest
ПостроениеПоследовательное (M деревьев)Параллельное (N деревьев)
ЗависимостьКаждое дерево зависит от предыдущихДеревья независимы
BiasНизкийСредний
VarianceМожет быть высокойНизкая
Learning rateВажный параметрНе применяется
Скорость обученияМедленнее (последовательно)Быстрее (параллельно)
КачествоОбычно лучшеХорошее

Практические советы

# Стратегия для хорошего GB регрессора:

# 1. Начни с простых параметров
model = GradientBoostingRegressor(
    n_estimators=100,
    learning_rate=0.1,
    max_depth=3-4,  # неглубокие деревья!
    subsample=0.8,
    random_state=42
)

# 2. Используй validation curve для выбора n_estimators
from sklearn.model_selection import validation_curve

learning_curves = validation_curve(
    model, X_train, y_train,
    param_name='n_estimators',
    param_range=[10, 50, 100, 200, 500],
    cv=5,
    scoring='neg_mean_squared_error'
)
# Выбери n_estimators где CV error минимален

# 3. Если переобучается → уменьши learning_rate или max_depth
# 4. Если недообучается → увеличи n_estimators

# 5. Всегда проверяй feature importance
print(model.feature_importances_)

Резюме

Gradient Boosting Regressor:

  • Строит последовательность слабых деревьев, каждое исправляет ошибки предыдущих
  • Использует gradient loss function для направления поиска
  • Очень мощный и гибкий алгоритм
  • Требует careful tuning параметров
  • Часто показывает SOTA результаты на табличных данных