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

Как устроен boosting?

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

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

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

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

Как устроен boosting?

Boosting — мощная техника ансамблевого обучения, которая последовательно обучает слабые классификаторы, где каждый новый классификатор фокусируется на примерах, которые предыдущие модели неправильно классифицировали.

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

Boosting работает итеративно:

Итерация 1: Обучаем модель на всех данных с одинаковыми весами
Ошибка: некоторые примеры классифицированы неверно
↓
Итерация 2: Увеличиваем веса неправильно классифицированных примеров
        Обучаем новую модель, она сосредоточится на трудных примерах
↓
Итерация 3: Повторяем процесс
↓
Финальный предсказание = взвешенная сумма всех моделей

2. AdaBoost (Adaptive Boosting)

Один из первых и простейших алгоритмов boosting:

import numpy as np
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score

class SimpleAdaBoost:
    def __init__(self, n_iterations=10):
        self.n_iterations = n_iterations
        self.models = []
        self.alphas = []
    
    def fit(self, X, y):
        """
        Обучение AdaBoost
        
        X: признаки (shape: n_samples, n_features)
        y: целевая переменная (shape: n_samples,) - должны быть 0 и 1 или -1 и 1
        """
        
        n_samples = X.shape[0]
        
        # Инициализируем все примеры с одинаковым весом
        weights = np.ones(n_samples) / n_samples
        
        for iteration in range(self.n_iterations):
            # Шаг 1: Обучаем слабый классификатор на взвешенных данных
            # Используем Decision Tree глубины 1 (пень решений)
            clf = DecisionTreeClassifier(max_depth=1, random_state=42)
            
            # Обучаем с весами (sklearn поддерживает это через sample_weight)
            clf.fit(X, y, sample_weight=weights)
            
            # Шаг 2: Вычисляем взвешенную ошибку
            y_pred = clf.predict(X)
            incorrect = (y_pred != y).astype(int)
            weighted_error = np.sum(weights * incorrect) / np.sum(weights)
            
            print(f'Итерация {iteration + 1}: ошибка = {weighted_error:.4f}')
            
            # Если ошибка >= 0.5, прерываем обучение
            if weighted_error >= 0.5:
                print('Ошибка >= 0.5, прерываем')
                break
            
            # Шаг 3: Вычисляем alpha (коэффициент модели)
            # Более точные модели получают больший коэффициент
            alpha = 0.5 * np.log((1 - weighted_error) / weighted_error)
            
            # Шаг 4: Обновляем веса примеров
            # Неправильно классифицированные примеры получают больший вес
            # exp(alpha) если ошибка, exp(-alpha) если верно
            weights = weights * np.exp(-alpha * y * y_pred)
            weights = weights / np.sum(weights)  # Нормализуем
            
            self.models.append(clf)
            self.alphas.append(alpha)
    
    def predict(self, X):
        """
        Предсказание: взвешенная сумма всех моделей
        """
        predictions = np.zeros(X.shape[0])
        
        for clf, alpha in zip(self.models, self.alphas):
            predictions += alpha * clf.predict(X)
        
        # Возвращаем знак (положительный = класс 1, отрицательный = класс 0)
        return np.sign(predictions)

# Пример использования
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split

X, y = make_classification(n_samples=200, n_features=10, n_informative=5, random_state=42)
y = 2 * y - 1  # Преобразуем в -1 и 1

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

ada = SimpleAdaBoost(n_iterations=10)
ada.fit(X_train, y_train)

y_pred = ada.predict(X_test)
accuracy = np.mean(y_pred == y_test)
print(f'\nТочность на тесте: {accuracy:.3f}')

3. Gradient Boosting

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

class SimpleGradientBoosting:
    def __init__(self, n_iterations=100, learning_rate=0.1):
        self.n_iterations = n_iterations
        self.learning_rate = learning_rate  # Шаг обучения
        self.models = []
        self.initial_prediction = None
    
    def fit(self, X, y):
        """
        Обучение Gradient Boosting для регрессии
        """
        
        # Начальное предсказание (средне значение)
        self.initial_prediction = np.mean(y)
        predictions = np.ones(X.shape[0]) * self.initial_prediction
        
        for iteration in range(self.n_iterations):
            # Вычисляем остатки (residuals) - ошибки текущих предсказаний
            residuals = y - predictions
            
            # Обучаем новую модель предсказывать остатки
            clf = DecisionTreeRegressor(max_depth=3, random_state=42)
            clf.fit(X, residuals)
            
            # Получаем предсказания остатков
            residual_predictions = clf.predict(X)
            
            # Обновляем общие предсказания
            # Используем learning_rate для контроля шага
            predictions += self.learning_rate * residual_predictions
            
            # Вычисляем ошибку
            mse = np.mean((y - predictions) ** 2)
            
            if iteration % 20 == 0:
                print(f'Итерация {iteration}: MSE = {mse:.4f}')
            
            self.models.append(clf)
    
    def predict(self, X):
        """
        Предсказание: сумма предсказаний всех моделей
        """
        predictions = np.ones(X.shape[0]) * self.initial_prediction
        
        for clf in self.models:
            predictions += self.learning_rate * clf.predict(X)
        
        return predictions

from sklearn.tree import DecisionTreeRegressor
from sklearn.datasets import make_regression

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

gb = SimpleGradientBoosting(n_iterations=100, learning_rate=0.1)
gb.fit(X_train, y_train)

y_pred = gb.predict(X_test)
mse = np.mean((y_test - y_pred) ** 2)
print(f'\nMSE на тесте: {mse:.4f}')

4. XGBoost — Production-версия Gradient Boosting

XGBoost добавляет регуляризацию и другие оптимизации:

from xgboost import XGBClassifier, XGBRegressor
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, roc_auc_score

# Классификация
X, y = load_breast_cancer(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

model = XGBClassifier(
    n_estimators=100,           # Количество деревьев
    max_depth=5,                # Максимальная глубина дерева
    learning_rate=0.1,          # Шаг обучения (eta)
    subsample=0.8,              # Доля примеров для обучения каждого дерева
    colsample_bytree=0.8,       # Доля признаков
    objective='binary:logistic', # Для бинарной классификации
    eval_metric='auc',
    random_state=42
)

model.fit(X_train, y_train, eval_set=[(X_test, y_test)], verbose=10)

y_pred = model.predict(X_test)
y_pred_proba = model.predict_proba(X_test)[:, 1]

accuracy = accuracy_score(y_test, y_pred)
auc = roc_auc_score(y_test, y_pred_proba)

print(f'Точность: {accuracy:.3f}')
print(f'AUC-ROC: {auc:.3f}')

5. LightGBM — быстрый альтернативный boosting

from lightgbm import LGBMRegressor

model = LGBMRegressor(
    n_estimators=200,
    max_depth=7,
    learning_rate=0.05,
    num_leaves=31,           # Количество листьев в дереве
    subsample=0.8,
    colsample_bytree=0.8,
    verbose=50
)

model.fit(X_train, y_train, eval_set=[(X_test, y_test)])

y_pred = model.predict(X_test)
mse = np.mean((y_test - y_pred) ** 2)
print(f'MSE: {mse:.4f}')

6. CatBoost — для категориальных признаков

from catboost import CatBoostClassifier

model = CatBoostClassifier(
    iterations=100,
    depth=6,
    learning_rate=0.1,
    loss_function='Logloss',
    cat_features=[0, 1, 2],  # Индексы категориальных признаков
    verbose=0,
    random_state=42
)

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

Параметры boosting и их влияние

n_estimators (количество итераций):

  • Больше → больше мощности, но рост времени обучения
  • Оптимально: 100-500 деревьев

learning_rate (шаг обучения):

  • Маленький (0.01-0.05) → медленное обучение, но более стабильно
  • Большой (0.1-0.3) → быстрое обучение, но может переобучиться

max_depth (глубина дерева):

  • Маленькая (3-7) → слабые модели, но быстрое обучение
  • Большая (10+) → мощные модели, риск переобучения

subsample (доля примеров):

  • < 1.0 добавляет стохастичность и предотвращает переобучение
  • Обычно 0.7-0.8

colsample_bytree (доля признаков):

  • Выбирает случайное подмножество признаков для каждого дерева
  • Снижает корреляцию между деревьями

Преимущества и недостатки

Преимущества:

  • Очень высокая точность (часто лучшие результаты в соревнованиях)
  • Автоматическая обработка взаимодействия признаков
  • Стабилен для разных типов данных
  • Отличная интерпретируемость (feature importance)

Недостатки:

  • Требует больше вычислительных ресурсов
  • Медленнее, чем случайный лес (sequential обучение)
  • Требует тщательной настройки гиперпараметров
  • Риск переобучения при неправильной настройке

Boosting — один из самых мощных методов машинного обучения и часто выбирается для решения real-world задач!

Как устроен boosting? | PrepBro