Agregación Bootstrap (Bagging) en Python
Aprende cómo el bagging reduce la varianza en modelos ML y cómo implementar BaggingClassifier en Python con scikit-learn.
La agregación Bootstrap — comúnmente llamada bagging — es una técnica de conjunto que entrena múltiples modelos sobre distintas muestras aleatorias de los datos y luego combina sus predicciones. El resultado es un modelo menos sensible al ruido y a los valores atípicos, que generaliza mejor ante datos no vistos que cualquier modelo individual entrenado con el conjunto completo.
Este capítulo abarca:
- Qué es el muestreo bootstrap y por qué resulta útil
- El compromiso sesgo–varianza que el bagging aborda
- Cómo implementar
BaggingClassifieryBaggingRegressorcon scikit-learn - Los hiperparámetros clave y cómo ajustarlos
- El error fuera de bolsa (OOB) como estimación gratuita de validación
- Cuándo conviene usar bagging y cuándo preferir otros métodos
Cómo funciona el muestreo bootstrap
La palabra bootstrap hace referencia al muestreo con reemplazo. Dado un conjunto de datos de n ejemplos, una muestra bootstrap se crea extrayendo n ejemplos al azar, donde cada extracción es independiente y el mismo ejemplo puede aparecer más de una vez.
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)Salida:
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]En promedio, una muestra bootstrap contiene alrededor del 63 % de los ejemplos originales únicos; el 37 % restante queda fuera. Estos ejemplos fuera de bolsa (OOB) pueden usarse como conjunto de validación integrado sin necesidad de una partición de retención separada.
El compromiso sesgo–varianza
Todo modelo realiza predicciones con alguna combinación de sesgo (error sistemático derivado de suposiciones incorrectas) y varianza (sensibilidad a las fluctuaciones en los datos de entrenamiento). El bagging apunta a modelos con alta varianza y bajo sesgo — en particular, árboles de decisión profundos.
Un único árbol de decisión sin poda puede memorizar perfectamente el conjunto de entrenamiento, pero falla notablemente con datos nuevos. Al promediar las predicciones de muchos árboles, cada uno entrenado con una muestra bootstrap ligeramente distinta, las fluctuaciones aleatorias se cancelan y la varianza disminuye — sin incrementar el sesgo de manera significativa.
El bagging no ayuda a modelos que ya tienen alto sesgo (por ejemplo, modelos lineales poco profundos), porque promediar muchos modelos sesgados sigue produciendo una respuesta sesgada. Para esos casos, los métodos de boosting como Gradient Boosting son más apropiados.
Implementando BaggingClassifier
scikit-learn proporciona BaggingClassifier para tareas de clasificación. El ejemplo a continuación compara un único árbol de decisión contra un conjunto basado en bagging sobre el conjunto de datos de cáncer de mama.
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}")Salida:
Single tree accuracy: 0.95
Bagging accuracy: 0.96El modelo con bagging supera al árbol individual. En conjuntos de datos más ruidosos o pequeños, la diferencia suele ser mayor.
Parámetros clave del constructor
| Parámetro | Valor por defecto | Lo que controla |
|---|---|---|
estimator | DecisionTreeClassifier() | El aprendiz base a agregar |
n_estimators | 10 | Número de modelos a entrenar |
max_samples | 1.0 | Fracción (o cantidad) de filas de entrenamiento por muestra bootstrap |
max_features | 1.0 | Fracción (o cantidad) de características para cada aprendiz base |
bootstrap | True | Muestrea filas con reemplazo; usa False para pegado (pasting) |
bootstrap_features | False | También muestrea características con reemplazo |
oob_score | False | Estima la generalización usando ejemplos fuera de bolsa |
Error fuera de bolsa (OOB)
Como cada aprendiz base solo ve aproximadamente el 63 % de los datos de entrenamiento, el 37 % restante puede usarse para evaluar ese aprendiz sin tocar el conjunto de prueba. Promediar estas evaluaciones OOB entre todos los estimadores produce la puntuación OOB — una estimación casi gratuita de la precisión en prueba.
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}")Salida:
OOB score: 0.96La puntuación OOB es cercana a la precisión del conjunto de prueba retenido, lo que la hace útil como verificación rápida — especialmente cuando el conjunto de datos es demasiado pequeño para dedicar una partición de validación separada. Para una estimación más rigurosa, combina el bagging con validación cruzada.
BaggingRegressor
El bagging es igualmente útil para regresión. Reemplaza BaggingClassifier con BaggingRegressor y elige un aprendiz base de regresión.
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}")Salida:
BaggingRegressor RMSE: 0.5080Evaluación con validación cruzada
Una sola partición entrenamiento-prueba puede ofrecer una imagen demasiado optimista o pesimista dependiendo de qué ejemplos caen en cada partición. Ejecutar validación cruzada promedia el resultado entre múltiples particiones para obtener una puntuación más confiable.
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}")Salida:
CV scores: [0.9123 0.9211 0.9825 0.9561 1. ]
Mean: 0.9544, Std: 0.0339Una desviación estándar baja entre los pliegues indica que el modelo generaliza de forma consistente. Una desviación estándar alta sugiere que el modelo es sensible a qué datos terminan en cada pliegue.
Bagging vs. Random Forest
Random Forest es el algoritmo basado en bagging más popular. Extiende el bagging simple seleccionando también aleatoriamente un subconjunto de características en cada decisión de división — no solo un subconjunto de filas —, lo que descorrelaciona aún más los árboles y generalmente produce mejor precisión.
| Bagging | Random Forest | |
|---|---|---|
| Muestreo de filas | Bootstrap (con reemplazo) | Bootstrap (con reemplazo) |
| Muestreo de características | Opcional (max_features) | Siempre, en cada división |
| Aprendiz base | Cualquier estimador | Solo árbol de decisión |
| Interpretabilidad | Baja | Baja |
| Uso típico | Cuando deseas agregar un modelo no basado en árboles | Mejor línea base de conjunto general |
Cuando se agregan árboles de decisión con bagging, RandomForestClassifier es casi siempre la mejor opción. Usa BaggingClassifier cuando quieras agregar un aprendiz base distinto — por ejemplo, un KNeighborsClassifier de K-Nearest Neighbors o una regresión logística de Logistic Regression.
Cuándo usar bagging
El bagging es más efectivo cuando:
- Tu modelo base tiene alta varianza (árboles de decisión profundos, modelos polinomiales de alto grado).
- Tienes suficientes datos para que las muestras bootstrap diversas sean significativas.
- Puedes costear el entrenamiento en paralelo, porque cada aprendiz base se entrena de forma independiente y la carga de trabajo puede distribuirse entre núcleos de CPU (
n_jobs=-1).
Es menos útil cuando:
- El modelo base ya tiene baja varianza (por ejemplo, modelos lineales con regularización fuerte).
- Necesitas un modelo único e interpretable — un conjunto de 50 árboles no es fácil de explicar a un interesado.
- El costo computacional importa más que la precisión — entrenar 50 modelos es 50 veces más lento que entrenar uno.
Para modelos con alto sesgo, considera Grid Search para ajustar hiperparámetros, o cambia a un método de boosting. Para la evaluación, verifica siempre tu modelo en una partición retenida creada con train-test split o con validación cruzada.
Resumen
- La agregación Bootstrap entrena muchos aprendices base sobre muestras aleatorias de los datos (extraídas con reemplazo) y promedia sus predicciones.
- Reduce la varianza sin incrementar significativamente el sesgo, lo que la hace ideal para modelos con alta varianza como los árboles de decisión profundos.
- scikit-learn proporciona
BaggingClassifieryBaggingRegressor; los parámetros clave sonn_estimators,max_samplesymax_features. - Activa
oob_score=Truepara obtener una estimación gratuita de generalización que no requiere un conjunto de validación separado. - Cuando se agregan árboles con bagging,
RandomForestClassifiersuele ser preferible; usaBaggingClassifierpara agregar otros tipos de modelos.