Как работает gradient-boosting регрессор?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Как работает 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 Boosting | Random 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 результаты на табличных данных