W3docs

Bootstrap Aggregation (Bagging) in Python

Scopri come il bagging riduce la varianza nei modelli ML e come implementare BaggingClassifier in Python con scikit-learn.

La bootstrap aggregation — comunemente chiamata bagging — è una tecnica di ensemble che addestra più modelli su campioni casuali diversi dei tuoi dati e poi combina le loro previsioni. Il risultato è un modello meno sensibile al rumore e agli outlier, che generalizza meglio su dati non visti rispetto a qualsiasi singolo modello addestrato sull'intero dataset.

Questo capitolo tratta:

  • Cos'è il campionamento bootstrap e perché è utile
  • Il compromesso bias–varianza che il bagging affronta
  • Come implementare BaggingClassifier e BaggingRegressor con scikit-learn
  • I principali iperparametri e come regolarli
  • L'errore out-of-bag (OOB) come stima di validazione gratuita
  • Quando il bagging è utile e quando preferire altri metodi

Come funziona il campionamento bootstrap

Il termine bootstrap si riferisce al campionamento con reinserimento. Dato un dataset di n esempi, un campione bootstrap viene creato estraendo n esempi a caso, dove ogni estrazione è indipendente e lo stesso esempio può apparire più di una volta.

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)

Output:

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]

In media, un campione bootstrap contiene circa il 63 % degli esempi originali unici; il restante 37 % viene escluso. Questi esempi out-of-bag (OOB) possono essere usati come set di validazione integrato senza necessità di una suddivisione hold-out separata.

Il compromesso bias–varianza

Ogni modello produce previsioni con una certa combinazione di bias (errore sistematico dovuto a ipotesi errate) e varianza (sensibilità alle fluttuazioni nei dati di addestramento). Il bagging si rivolge ai modelli con alta varianza e basso bias — in particolare agli alberi decisionali profondi.

Un singolo albero decisionale non potato può memorizzare perfettamente il training set, ma fallisce notevolmente su nuovi dati. Mediando le previsioni di molti alberi, ciascuno addestrato su un campione bootstrap leggermente diverso, le fluttuazioni casuali si annullano e la varianza diminuisce — senza aumentare significativamente il bias.

Il bagging non aiuta i modelli che hanno già un bias elevato (ad esempio, i modelli lineari poco profondi), perché mediare molti modelli distorti produce comunque una risposta distorta. In questi casi, metodi di boosting come Gradient Boosting sono più appropriati.

Implementare BaggingClassifier

scikit-learn fornisce BaggingClassifier per i task di classificazione. L'esempio seguente confronta un singolo albero decisionale con un ensemble con bagging sul dataset breast cancer.

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}")

Output:

Single tree accuracy:  0.95
Bagging accuracy:      0.96

Il modello con bagging supera il singolo albero. Su dataset più rumorosi o più piccoli, il margine è generalmente maggiore.

Parametri principali del costruttore

ParametroPredefinitoCosa controlla
estimatorDecisionTreeClassifier()Il base learner da aggregare
n_estimators10Numero di modelli da addestrare
max_samples1.0Frazione (o numero) di righe del training per campione bootstrap
max_features1.0Frazione (o numero) di feature estratte per ogni base learner
bootstrapTrueCampiona le righe con reinserimento; impostare False per il pasting
bootstrap_featuresFalseCampiona anche le feature con reinserimento
oob_scoreFalseStima la generalizzazione usando gli esempi out-of-bag

Errore out-of-bag (OOB)

Poiché ogni base learner vede circa il 63 % dei dati di addestramento, il restante 37 % può essere usato per valutare quel learner senza toccare il test set. Mediando queste valutazioni OOB su tutti gli estimatori si ottiene l'OOB score — una stima quasi gratuita dell'accuratezza sul test.

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}")

Output:

OOB score: 0.96

L'OOB score è vicino all'accuratezza sul test set trattenuto, il che lo rende utile come verifica rapida — soprattutto quando il dataset è troppo piccolo per permettersi una suddivisione di validazione separata. Per una stima più rigorosa, abbina il bagging alla cross-validation.

BaggingRegressor

Il bagging è ugualmente utile per la regressione. Sostituisci BaggingClassifier con BaggingRegressor e scegli un base learner per la regressione.

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}")

Output:

BaggingRegressor RMSE: 0.5080

Valutazione con cross-validation

Una singola suddivisione train-test può dare un quadro eccessivamente ottimistico o pessimistico a seconda di quali esempi finiscono in ogni partizione. Eseguire la cross-validation media il risultato su più suddivisioni per ottenere un punteggio più affidabile.

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}")

Output:

CV scores: [0.9123 0.9211 0.9825 0.9561 1.    ]
Mean: 0.9544, Std: 0.0339

Una bassa deviazione standard tra i fold indica che il modello generalizza in modo costante. Un'alta deviazione standard suggerisce che il modello è sensibile a quali dati finiscono in ogni fold.

Bagging vs. Random Forest

Random Forest è l'algoritmo basato sul bagging più popolare. Estende il bagging semplice selezionando casualmente anche un sottoinsieme di feature ad ogni decisione di split — non solo un sottoinsieme di righe — il che decorrelata ulteriormente gli alberi e spesso fornisce una migliore accuratezza.

BaggingRandom Forest
Campionamento delle righeBootstrap (con reinserimento)Bootstrap (con reinserimento)
Campionamento delle featureOpzionale (max_features)Sempre, ad ogni split
Base learnerQualsiasi estimatoreSolo albero decisionale
InterpretabilitàBassaBassa
Uso tipicoQuando si vuole aggregare un modello non ad alberoMiglior baseline ensemble universale

Quando si aggregano alberi decisionali, RandomForestClassifier è quasi sempre la scelta migliore. Usa BaggingClassifier quando vuoi aggregare un base learner diverso — ad esempio, un KNeighborsClassifier da K-Nearest Neighbors o una regressione logistica da Logistic Regression.

Quando usare il bagging

Il bagging è più efficace quando:

  • Il tuo modello base ha alta varianza (alberi decisionali profondi, modelli polinomiali di grado elevato).
  • Hai abbastanza dati per rendere significativi i campioni bootstrap diversificati.
  • Puoi permetterti un addestramento parallelo, perché ogni base learner si addestra in modo indipendente e il carico di lavoro può essere distribuito tra i core della CPU (n_jobs=-1).

È meno utile quando:

  • Il modello base ha già bassa varianza (ad es., modelli lineari con forte regolarizzazione).
  • Hai bisogno di un modello singolo e interpretabile — un ensemble di 50 alberi non è facile da spiegare a uno stakeholder.
  • Il costo computazionale è più importante dell'accuratezza — addestrare 50 modelli è 50 volte più lento che addestrarne uno.

Per i modelli ad alto bias, considera Grid Search per ottimizzare gli iperparametri, oppure passa a un metodo di boosting. Per la valutazione, verifica sempre il tuo modello su una suddivisione hold-out creata con train-test split o con la cross-validation.

  • La bootstrap aggregation addestra molti base learner su campioni casuali dei dati (estratti con reinserimento) e ne media le previsioni.
  • Riduce la varianza senza aumentare significativamente il bias, rendendola ideale per i modelli ad alta varianza come gli alberi decisionali profondi.
  • scikit-learn fornisce BaggingClassifier e BaggingRegressor; i parametri chiave sono n_estimators, max_samples e max_features.
  • Abilita oob_score=True per una stima gratuita della generalizzazione che non richiede un set di validazione separato.
  • Quando si aggregano alberi, RandomForestClassifier è generalmente preferibile; usa BaggingClassifier per aggregare altri tipi di modello.
Was this page helpful?