Bootstrap Aggregation (Bagging) in Python
Lerne, wie Bagging die Varianz in ML-Modellen reduziert und wie du BaggingClassifier in Python implementierst.
Bootstrap Aggregation — häufig als Bagging bezeichnet — ist eine Ensemble-Technik, die mehrere Modelle auf verschiedenen zufälligen Stichproben deiner Daten trainiert und anschließend deren Vorhersagen kombiniert. Das Ergebnis ist ein Modell, das weniger empfindlich gegenüber Rauschen und Ausreißern ist und besser auf unbekannte Daten verallgemeinert als ein einzelnes Modell, das auf dem gesamten Datensatz trainiert wurde.
Dieses Kapitel behandelt:
- Was Bootstrap-Sampling ist und warum es hilft
- Den Bias-Varianz-Kompromiss, den Bagging adressiert
- Wie man
BaggingClassifierundBaggingRegressormit scikit-learn implementiert - Wichtige Hyperparameter und wie man sie abstimmt
- Out-of-Bag (OOB)-Fehler als kostenlosen Validierungsschätzer
- Wann Bagging hilft und wann andere Methoden vorzuziehen sind
Wie Bootstrap-Sampling funktioniert
Das Wort Bootstrap bezieht sich auf Sampling mit Zurücklegen. Gegeben ein Datensatz mit n Beispielen wird eine Bootstrap-Stichprobe erstellt, indem n Beispiele zufällig gezogen werden, wobei jeder Zug unabhängig ist und dasselbe Beispiel mehr als einmal erscheinen kann.
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)Ausgabe:
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]Im Durchschnitt enthält eine Bootstrap-Stichprobe etwa 63 % der einzigartigen Originalbeispiele; die verbleibenden 37 % werden ausgelassen. Diese Out-of-Bag-(OOB-)Beispiele können als integriertes Validierungsset verwendet werden, ohne dass eine separate Hold-out-Aufteilung benötigt wird.
Der Bias-Varianz-Kompromiss
Jedes Modell macht Vorhersagen mit einer Kombination aus Bias (systematischer Fehler durch falsche Annahmen) und Varianz (Empfindlichkeit gegenüber Schwankungen in den Trainingsdaten). Bagging zielt auf Modelle mit hoher Varianz und niedrigem Bias ab — insbesondere tiefe Entscheidungsbäume.
Ein einzelner unbeschnittener Entscheidungsbaum kann den Trainingsdatensatz perfekt auswendig lernen, versagt jedoch auf neuen Daten. Indem die Vorhersagen vieler Bäume gemittelt werden, die jeweils auf einer leicht unterschiedlichen Bootstrap-Stichprobe trainiert wurden, heben sich die zufälligen Schwankungen auf und die Varianz sinkt — ohne den Bias wesentlich zu erhöhen.
Bagging hilft nicht bei Modellen, die bereits einen hohen Bias haben (zum Beispiel flache lineare Modelle), da das Mitteln vieler verzerrter Modelle immer noch ein verzerrtes Ergebnis liefert. Für diese Fälle sind Boosting-Methoden wie Gradient Boosting besser geeignet.
BaggingClassifier implementieren
scikit-learn stellt BaggingClassifier für Klassifikationsaufgaben bereit. Das folgende Beispiel vergleicht einen einzelnen Entscheidungsbaum mit einem gebaggerten Ensemble auf dem Brustkrebs-Datensatz.
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}")Ausgabe:
Single tree accuracy: 0.95
Bagging accuracy: 0.96Das gebaggerte Modell übertrifft den einzelnen Baum. Bei verrauschteren oder kleineren Datensätzen ist der Unterschied in der Regel größer.
Wichtige Konstruktorparameter
| Parameter | Standard | Was er steuert |
|---|---|---|
estimator | DecisionTreeClassifier() | Der zu baggernde Basis-Lerner |
n_estimators | 10 | Anzahl der zu trainierenden Modelle |
max_samples | 1.0 | Anteil (oder Anzahl) der Trainingszeilen pro Bootstrap-Stichprobe |
max_features | 1.0 | Anteil (oder Anzahl) der für jeden Basis-Lerner gezogenen Merkmale |
bootstrap | True | Zeilen mit Zurücklegen sampeln; auf False setzen für Pasting |
bootstrap_features | False | Merkmale ebenfalls mit Zurücklegen sampeln |
oob_score | False | Generalisierung mithilfe von Out-of-Bag-Beispielen schätzen |
Out-of-Bag (OOB)-Fehler
Da jeder Basis-Lerner nur etwa 63 % der Trainingsdaten sieht, können die verbleibenden 37 % zur Auswertung dieses Lerners verwendet werden, ohne das Testset zu berühren. Das Mitteln dieser OOB-Auswertungen über alle Schätzer hinweg ergibt den OOB-Score — einen nahezu kostenlosen Schätzer der Testgenauigkeit.
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}")Ausgabe:
OOB score: 0.96Der OOB-Score liegt nahe an der gehaltenen Testgenauigkeit und ist daher als schnelle Plausibilitätsprüfung nützlich — besonders wenn dein Datensatz zu klein ist, um eine separate Validierungsaufteilung zu erlauben. Für eine genauere Schätzung kombiniere Bagging mit Kreuzvalidierung.
BaggingRegressor
Bagging ist auch für Regression nützlich. Ersetze BaggingClassifier durch BaggingRegressor und wähle einen Regressions-Basis-Lerner.
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}")Ausgabe:
BaggingRegressor RMSE: 0.5080Auswertung mit Kreuzvalidierung
Eine einzelne Train-Test-Aufteilung kann je nachdem, welche Beispiele in welche Partition fallen, ein übermäßig optimistisches oder pessimistisches Bild ergeben. Die Ausführung von Kreuzvalidierung mittelt das Ergebnis über mehrere Aufteilungen hinweg für einen zuverlässigeren Score.
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}")Ausgabe:
CV scores: [0.9123 0.9211 0.9825 0.9561 1. ]
Mean: 0.9544, Std: 0.0339Eine niedrige Standardabweichung über die Faltungen hinweg bedeutet, dass das Modell konsistent generalisiert. Eine hohe Standardabweichung deutet darauf hin, dass das Modell empfindlich darauf reagiert, welche Daten in welche Faltung gelangen.
Bagging vs. Random Forest
Random Forest ist der beliebteste Bagging-basierte Algorithmus. Er erweitert einfaches Bagging, indem bei jeder Teilungsentscheidung zusätzlich eine zufällige Teilmenge von Merkmalen ausgewählt wird — nicht nur eine Teilmenge von Zeilen —, was die Bäume weiter dekorreliert und häufig eine bessere Genauigkeit erzielt.
| Bagging | Random Forest | |
|---|---|---|
| Zeilen-Sampling | Bootstrap (mit Zurücklegen) | Bootstrap (mit Zurücklegen) |
| Merkmal-Sampling | Optional (max_features) | Immer, bei jeder Teilung |
| Basis-Lerner | Beliebiger Schätzer | Nur Entscheidungsbaum |
| Interpretierbarkeit | Niedrig | Niedrig |
| Typischer Einsatz | Wenn ein Nicht-Baum-Modell gebaggert werden soll | Bester allgemeiner Ensemble-Ausgangspunkt |
Wenn Entscheidungsbäume gebaggert werden, ist RandomForestClassifier fast immer die bessere Wahl. Verwende BaggingClassifier, wenn du einen anderen Basis-Lerner baggern möchtest — zum Beispiel einen KNeighborsClassifier aus K-Nearest Neighbors oder eine logistische Regression aus Logistic Regression.
Wann Bagging eingesetzt werden sollte
Bagging ist am effektivsten, wenn:
- Dein Basismodell eine hohe Varianz hat (tiefe Entscheidungsbäume, Polynommodelle hohen Grades).
- Du genug Daten hast, um diverse Bootstrap-Stichproben sinnvoll zu machen.
- Du dir paralleles Training leisten kannst, da jeder Basis-Lerner unabhängig trainiert und die Arbeitslast auf CPU-Kerne verteilt werden kann (
n_jobs=-1).
Es ist weniger hilfreich, wenn:
- Das Basismodell bereits eine niedrige Varianz hat (z. B. lineare Modelle mit starker Regularisierung).
- Du ein einzelnes, interpretierbares Modell benötigst — ein Ensemble aus 50 Bäumen lässt sich einem Stakeholder nicht leicht erklären.
- Rechenkosten wichtiger sind als Genauigkeit — das Training von 50 Modellen ist 50-mal langsamer als das Training eines einzelnen.
Für Modelle mit hohem Bias solltest du Grid Search zur Hyperparameter-Abstimmung in Betracht ziehen oder zu einer Boosting-Methode wechseln. Zur Auswertung überprüfe dein Modell immer auf einer Hold-out-Aufteilung, die mit Train-Test-Split oder Kreuzvalidierung erstellt wurde.
Zusammenfassung
- Bootstrap Aggregation trainiert viele Basis-Lerner auf zufälligen Stichproben der Daten (mit Zurücklegen gezogen) und mittelt deren Vorhersagen.
- Es reduziert die Varianz, ohne den Bias wesentlich zu erhöhen, und ist damit ideal für Modelle mit hoher Varianz wie tiefe Entscheidungsbäume.
- scikit-learn stellt
BaggingClassifierundBaggingRegressorbereit; wichtige Parameter sindn_estimators,max_samplesundmax_features. - Aktiviere
oob_score=Truefür einen kostenlosen Generalisierungsschätzer, der kein separates Validierungsset erfordert. - Beim Baggern von Bäumen ist
RandomForestClassifierin der Regel vorzuziehen; verwendeBaggingClassifier, um andere Modelltypen zu baggern.