Bootstrap Aggregation (Bagging) в Python
Узнайте, как бэггинг снижает дисперсию ML-моделей и как реализовать BaggingClassifier в Python.
Bootstrap aggregation — широко известный как бэггинг — это ансамблевый метод, при котором несколько моделей обучаются на разных случайных выборках ваших данных, а затем их предсказания объединяются. В результате получается модель, менее чувствительная к шуму и выбросам, которая лучше обобщается на новых данных, чем любая отдельная модель, обученная на всём датасете.
В этой главе рассматривается:
- Что такое бутстрэп-выборка и почему она помогает
- Компромисс между смещением и дисперсией, который решает бэггинг
- Как реализовать
BaggingClassifierиBaggingRegressorс помощью scikit-learn - Ключевые гиперпараметры и способы их настройки
- Ошибка out-of-bag (OOB) как бесплатная оценка на валидационной выборке
- Когда бэггинг помогает, а когда лучше выбрать другие методы
Как работает бутстрэп-выборка
Слово bootstrap означает выборку с возвращением. Для датасета из n примеров одна бутстрэп-выборка создаётся путём случайного извлечения n примеров, где каждое извлечение независимо и один и тот же пример может встречаться более одного раза.
import numpy as np
rng = np.random.default_rng(42)
data = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
bootstrap_sample = rng.choice(data, size=len(data), replace=True)
out_of_bag = np.setdiff1d(data, bootstrap_sample)
print("Original data: ", data)
print("Bootstrap sample:", bootstrap_sample)
print("Out-of-bag: ", out_of_bag)Вывод:
Original data: [ 1 2 3 4 5 6 7 8 9 10]
Bootstrap sample: [1 8 7 5 5 9 1 7 3 1]
Out-of-bag: [ 2 4 6 10]В среднем бутстрэп-выборка содержит около 63 % уникальных оригинальных примеров; оставшиеся 37 % не попадают в неё. Эти примеры out-of-bag (OOB) можно использовать как встроенную валидационную выборку без необходимости делать отдельный отложенный раздел.
Компромисс между смещением и дисперсией
Каждая модель делает предсказания с некоторым сочетанием смещения (систематической ошибки из-за неверных допущений) и дисперсии (чувствительности к флуктуациям в обучающих данных). Бэггинг нацелен на модели с высокой дисперсией и низким смещением — в особенности на глубокие деревья решений.
Одно необрезанное дерево решений может идеально запомнить обучающую выборку, но плохо справляется с новыми данными. Усредняя предсказания множества деревьев, каждое из которых обучено на немного другой бутстрэп-выборке, случайные флуктуации компенсируют друг друга и дисперсия снижается — без существенного увеличения смещения.
Бэггинг не помогает моделям с высоким смещением (например, неглубоким линейным моделям), поскольку усреднение многих смещённых моделей всё равно даёт смещённый результат. В таких случаях более подходящими являются методы бустинга, такие как Gradient Boosting.
Реализация BaggingClassifier
scikit-learn предоставляет BaggingClassifier для задач классификации. В примере ниже сравнивается одиночное дерево решений с ансамблем на основе бэггинга на датасете рака молочной железы.
from sklearn.ensemble import BaggingClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_breast_cancer
from sklearn.metrics import accuracy_score
# Load dataset
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.2, random_state=42
)
# Baseline: single decision tree
single_tree = DecisionTreeClassifier(random_state=42)
single_tree.fit(X_train, y_train)
single_acc = accuracy_score(y_test, single_tree.predict(X_test))
# Bagging ensemble of 50 decision trees
bagging_model = BaggingClassifier(
estimator=DecisionTreeClassifier(),
n_estimators=50,
random_state=42,
)
bagging_model.fit(X_train, y_train)
bagging_acc = accuracy_score(y_test, bagging_model.predict(X_test))
print(f"Single tree accuracy: {single_acc:.2f}")
print(f"Bagging accuracy: {bagging_acc:.2f}")Вывод:
Single tree accuracy: 0.95
Bagging accuracy: 0.96Модель с бэггингом превосходит одиночное дерево. На более зашумлённых или небольших датасетах разрыв обычно больше.
Ключевые параметры конструктора
| Параметр | По умолчанию | Что контролирует |
|---|---|---|
estimator | DecisionTreeClassifier() | Базовый алгоритм для бэггинга |
n_estimators | 10 | Количество моделей для обучения |
max_samples | 1.0 | Доля (или количество) строк обучающей выборки на бутстрэп-выборку |
max_features | 1.0 | Доля (или количество) признаков для каждого базового алгоритма |
bootstrap | True | Выборка строк с возвращением; установите False для вставки без возвращения |
bootstrap_features | False | Также выбирать признаки с возвращением |
oob_score | False | Оценка обобщающей способности с помощью out-of-bag примеров |
Ошибка out-of-bag (OOB)
Поскольку каждый базовый алгоритм видит лишь около 63 % обучающих данных, оставшиеся 37 % можно использовать для его оценки, не затрагивая тестовую выборку. Усреднение этих OOB-оценок по всем оценщикам даёт OOB-оценку — практически бесплатную оценку точности на тестовой выборке.
from sklearn.ensemble import BaggingClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_breast_cancer
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.2, random_state=42
)
bagging_oob = BaggingClassifier(
estimator=DecisionTreeClassifier(),
n_estimators=50,
oob_score=True, # enable OOB evaluation
random_state=42,
)
bagging_oob.fit(X_train, y_train)
print(f"OOB score: {bagging_oob.oob_score_:.2f}")Вывод:
OOB score: 0.96OOB-оценка близка к точности на отложенной тестовой выборке, что делает её полезной для быстрой проверки — особенно когда датасет слишком мал для выделения отдельного раздела для валидации. Для более строгой оценки сочетайте бэггинг с кросс-валидацией.
BaggingRegressor
Бэггинг одинаково полезен для задач регрессии. Замените BaggingClassifier на BaggingRegressor и выберите базовый алгоритм регрессии.
from sklearn.ensemble import BaggingRegressor
from sklearn.tree import DecisionTreeRegressor
from sklearn.model_selection import train_test_split
from sklearn.datasets import fetch_california_housing
from sklearn.metrics import mean_squared_error
import numpy as np
X, y = fetch_california_housing(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
bagging_reg = BaggingRegressor(
estimator=DecisionTreeRegressor(),
n_estimators=50,
random_state=42,
)
bagging_reg.fit(X_train, y_train)
rmse = np.sqrt(mean_squared_error(y_test, bagging_reg.predict(X_test)))
print(f"BaggingRegressor RMSE: {rmse:.4f}")Вывод:
BaggingRegressor RMSE: 0.5080Оценка с помощью кросс-валидации
Единственное разбиение на обучающую и тестовую выборки может давать чрезмерно оптимистичный или пессимистичный результат в зависимости от того, какие примеры попадут в каждый раздел. Использование кросс-валидации усредняет результат по нескольким разбиениям для получения более надёжной оценки.
from sklearn.ensemble import BaggingClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import cross_val_score
from sklearn.datasets import load_breast_cancer
import numpy as np
X, y = load_breast_cancer(return_X_y=True)
clf = BaggingClassifier(
estimator=DecisionTreeClassifier(),
n_estimators=50,
random_state=42,
)
scores = cross_val_score(clf, X, y, cv=5)
print(f"CV scores: {scores.round(4)}")
print(f"Mean: {scores.mean():.4f}, Std: {scores.std():.4f}")Вывод:
CV scores: [0.9123 0.9211 0.9825 0.9561 1. ]
Mean: 0.9544, Std: 0.0339Низкое стандартное отклонение по фолдам означает, что модель обобщается стабильно. Высокое стандартное отклонение свидетельствует о том, что модель чувствительна к тому, какие данные попадают в каждый фолд.
Бэггинг против Random Forest
Random Forest — наиболее популярный алгоритм на основе бэггинга. Он расширяет обычный бэггинг, также случайным образом выбирая подмножество признаков при каждом разбиении узла — не только подмножество строк — что дополнительно декоррелирует деревья и зачастую даёт более высокую точность.
| Бэггинг | Random Forest | |
|---|---|---|
| Выборка строк | Bootstrap (с возвращением) | Bootstrap (с возвращением) |
| Выборка признаков | Опционально (max_features) | Всегда, при каждом разбиении |
| Базовый алгоритм | Любой оценщик | Только дерево решений |
| Интерпретируемость | Низкая | Низкая |
| Типичное применение | Когда нужно применить бэггинг к модели не на основе дерева | Лучшая базовая ансамблевая модель на все случаи |
Если вы применяете бэггинг к деревьям решений, RandomForestClassifier почти всегда является лучшим выбором. Используйте BaggingClassifier, когда хотите применить бэггинг к другому базовому алгоритму — например, к KNeighborsClassifier из раздела K-Nearest Neighbors или к логистической регрессии из раздела Logistic Regression.
Когда использовать бэггинг
Бэггинг наиболее эффективен, когда:
- Ваша базовая модель имеет высокую дисперсию (глубокие деревья решений, полиномиальные модели высокой степени).
- У вас достаточно данных для создания разнообразных бутстрэп-выборок.
- Вы можете позволить себе параллельное обучение, поскольку каждый базовый алгоритм обучается независимо и нагрузка может распределяться по ядрам CPU (
n_jobs=-1).
Бэггинг менее полезен, когда:
- Базовая модель уже имеет низкую дисперсию (например, линейные модели с сильной регуляризацией).
- Вам нужна единственная интерпретируемая модель — ансамбль из 50 деревьев сложно объяснить заинтересованному лицу.
- Вычислительные затраты важнее точности — обучение 50 моделей в 50 раз медленнее, чем обучение одной.
Для моделей с высоким смещением рассмотрите Grid Search для настройки гиперпараметров или переключитесь на метод бустинга. Для оценки всегда проверяйте модель на отложенной выборке, созданной с помощью train-test split или кросс-валидации.
Итоги
- Bootstrap aggregation обучает множество базовых алгоритмов на случайных выборках данных (с возвращением) и усредняет их предсказания.
- Метод снижает дисперсию без существенного увеличения смещения, что делает его идеальным для моделей с высокой дисперсией, таких как глубокие деревья решений.
- scikit-learn предоставляет
BaggingClassifierиBaggingRegressor; ключевые параметры:n_estimators,max_samplesиmax_features. - Включите
oob_score=Trueдля бесплатной оценки обобщающей способности без необходимости использовать отдельную валидационную выборку. - При бэггинге деревьев обычно предпочтителен
RandomForestClassifier; используйтеBaggingClassifierдля бэггинга других типов моделей.