Por qué salir del Gradient Boosting clásico de Scikit-learn
El GradientBoostingClassifier y GradientBoostingRegressor tradicionales de Scikit-learn son excelentes didácticamente, pero en la práctica profesional el estándar es otro. Scikit-learn ha incorporado HistGradientBoostingClassifier y HistGradientBoostingRegressor, basados en histogramas, que son mucho más rápidos y soportan valores faltantes y categóricas. Aun así, cuando necesitas el máximo rendimiento o características avanzadas se recurre a tres librerías externas ampliamente consolidadas: XGBoost, LightGBM y CatBoost.
flowchart LR
GB["GradientBoosting clásico\nsklearn.ensemble"] --> HGB["HistGradientBoosting\nsklearn 1.5+"]
HGB --> EXT[Librerías externas]
EXT --> XGB["XGBoost\ntablas medianas-grandes"]
EXT --> LGB["LightGBM\ndatasets muy grandes,\ncategóricas nativas"]
EXT --> CAT["CatBoost\ncategóricas de alta cardinalidad,\nordered boosting"]
XGB --> PIPE["Pipeline de\nScikit-learn"]
LGB --> PIPE
CAT --> PIPE
HGB --> PIPE
Las tres comparten el mismo patrón: algoritmos de gradient boosting sobre árboles de decisión, optimizados con histogramas, crecimiento leaf-wise y soporte nativo de paralelismo. La diferencia está en los detalles: velocidad, manejo de categóricas, consumo de memoria y estabilidad con clases desbalanceadas.
Instalación y API compatible
El primer paso es instalar las tres librerías. Todas ofrecen un wrapper compatible con la API de Scikit-learn (fit, predict, predict_proba, score), lo que las convierte en reemplazos directos del estimador final de un Pipeline.
pip install xgboost lightgbm catboost
A continuación vemos cómo cada una se comporta igual que un estimador de Scikit-learn:
from xgboost import XGBClassifier
from lightgbm import LGBMClassifier
from catboost import CatBoostClassifier
xgb = XGBClassifier(
n_estimators=300,
max_depth=6,
learning_rate=0.05,
objective="binary:logistic",
random_state=42,
)
lgbm = LGBMClassifier(
n_estimators=300,
max_depth=-1,
learning_rate=0.05,
num_leaves=31,
random_state=42,
)
cat = CatBoostClassifier(
iterations=300,
depth=6,
learning_rate=0.05,
verbose=False,
random_seed=42,
)
for modelo in (xgb, lgbm, cat):
modelo.fit(X_train, y_train)
print(modelo.__class__.__name__, modelo.score(X_test, y_test))
Integración con Pipeline y ColumnTransformer
Dado que respetan la API, puedes usarlos exactamente igual que cualquier estimador de Scikit-learn dentro de un Pipeline. En este ejemplo combinamos un ColumnTransformer que preprocesa numéricas y categóricas con un LGBMClassifier como estimador final:
import pandas as pd
from sklearn.compose import ColumnTransformer
from sklearn.impute import SimpleImputer
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from lightgbm import LGBMClassifier
num_cols = ["edad", "ingresos"]
cat_cols = ["sexo", "ciudad"]
preproc = ColumnTransformer(
transformers=[
(
"num",
Pipeline(steps=[
("imp", SimpleImputer(strategy="median")),
("sc", StandardScaler()),
]),
num_cols,
),
(
"cat",
Pipeline(steps=[
("imp", SimpleImputer(strategy="most_frequent")),
("oh", OneHotEncoder(handle_unknown="ignore")),
]),
cat_cols,
),
]
)
pipe = Pipeline(steps=[
("preproc", preproc),
("modelo", LGBMClassifier(n_estimators=300, learning_rate=0.05)),
])
pipe.fit(X_train, y_train)
LightGBM y CatBoost admiten variables categóricas sin codificación previa mediante el parámetro categorical_feature (LightGBM) o cat_features (CatBoost). En datasets con categorías de alta cardinalidad esto suele rendir mejor que aplicar OneHotEncoder, ya que evita explotar la dimensionalidad.
Criterios para elegir implementación
A igualdad de dataset y esfuerzo de tuneo, la elección suele seguir esta heurística:
HistGradientBoostingClassifierde Scikit-learn: primera opción cuando quieres mantener el proyecto con dependencias mínimas. Rendimiento muy cercano a XGBoost/LightGBM en problemas tabulares medianos.- XGBoost: estándar de facto en competiciones (Kaggle) y en equipos con infraestructura propia. Implementación muy madura, con soporte GPU y un ecosistema enorme de integraciones.
- LightGBM: preferido en datasets grandes por su velocidad (crecimiento leaf-wise, histogramas) y su manejo eficiente de categóricas de alta cardinalidad.
- CatBoost: cuando predominan variables categóricas. Su algoritmo ordered boosting reduce el sesgo de target leakage que sufren otras implementaciones al codificar categorías.
Ajuste de hiperparámetros con HalvingRandomSearchCV
Todas estas librerías tienen muchos hiperparámetros. En la práctica no se hace búsqueda exhaustiva: se usa HalvingRandomSearchCV de Scikit-learn para explorar un espacio amplio descartando rápido las combinaciones pobres.
from sklearn.experimental import enable_halving_search_cv # noqa: F401
from sklearn.model_selection import HalvingRandomSearchCV
from scipy.stats import loguniform, randint
param_dist = {
"modelo__n_estimators": randint(100, 800),
"modelo__num_leaves": randint(15, 127),
"modelo__learning_rate": loguniform(1e-3, 3e-1),
"modelo__min_child_samples": randint(5, 50),
}
search = HalvingRandomSearchCV(
estimator=pipe,
param_distributions=param_dist,
factor=3,
resource="n_samples",
scoring="roc_auc",
cv=5,
random_state=42,
n_jobs=-1,
)
search.fit(X_train, y_train)
print(search.best_params_, search.best_score_)
La clave es que el estimador de boosting vive dentro del Pipeline, por lo que los hiperparámetros llevan el prefijo modelo__. Esto garantiza que el preprocesado se aprenda solo con los datos de entrenamiento de cada pliegue, sin fuga de información.
Métrica de comparación honesta
Para comparar HistGradientBoostingClassifier, XGBClassifier, LGBMClassifier y CatBoostClassifier de forma justa usa validación cruzada estratificada y una métrica adecuada al problema (roc_auc para desbalanceo, f1 para clasificación binaria simétrica, neg_mean_absolute_error para regresión). Con cross_val_score y el mismo split de semilla el resultado es reproducible y comparable.
from sklearn.model_selection import cross_val_score, StratifiedKFold
from sklearn.ensemble import HistGradientBoostingClassifier
cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
candidatos = {
"hist": HistGradientBoostingClassifier(),
"xgb": XGBClassifier(eval_metric="logloss"),
"lgbm": LGBMClassifier(),
"cat": CatBoostClassifier(verbose=False),
}
for nombre, modelo in candidatos.items():
scores = cross_val_score(modelo, X_train, y_train, cv=cv, scoring="roc_auc")
print(f"{nombre}: {scores.mean():.4f} ± {scores.std():.4f}")
Caso B2B: scoring de fraude en transacciones bancarias
Un equipo de prevención de fraude procesa decenas de millones de transacciones al día. El dataset combina features numéricas (importe, ratio sobre gasto medio, hora), categóricas de alta cardinalidad (comercio, MCC, país) y un fuerte desbalanceo (fraude por debajo del 1%). En este escenario la elección natural es LightGBM por su manejo nativo de categóricas y el soporte de class_weight para compensar el desbalanceo.
import pandas as pd
from lightgbm import LGBMClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report, average_precision_score
df = pd.read_parquet("transacciones.parquet", dtype_backend="pyarrow")
X = df.drop(columns=["es_fraude"])
y = df["es_fraude"].astype(int)
cat_cols = ["comercio", "mcc", "pais"]
for col in cat_cols:
X[col] = X[col].astype("category")
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, stratify=y, random_state=42
)
modelo = LGBMClassifier(
n_estimators=500,
learning_rate=0.05,
num_leaves=63,
class_weight="balanced", # compensa el desbalanceo 1:99
categorical_feature=cat_cols, # LightGBM maneja categoricas sin encoding
random_state=42,
n_jobs=-1,
)
modelo.fit(X_train, y_train)
y_proba = modelo.predict_proba(X_test)[:, 1]
print(f"Average precision (AP): {average_precision_score(y_test, y_proba):.4f}")
print(classification_report(y_test, modelo.predict(X_test), digits=3))
Este flujo es el esqueleto recurrente en scoring de fraude y en scoring crediticio: dataset tabular desbalanceado, features mixtas, y un boosting como estimador final. La métrica de referencia es average precisión (área bajo la curva PR), mas robusta que ROC-AUC cuando la clase positiva es minoritaria.
Caso B2B: forecasting de demanda con XGBoost
Un distribuidor industrial predice la demanda semanal por SKU a partir de ventas históricas, lags, festivos y eventos promocionales. XGBoost es la opción estandar por madurez, soporte GPU y reproducibilidad.
from xgboost import XGBRegressor
from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import OneHotEncoder
pipe = Pipeline(steps=[
("preproc", ColumnTransformer([
("cat", OneHotEncoder(handle_unknown="ignore"),
["categoria_sku", "region"]),
], remainder="passthrough")),
("modelo", XGBRegressor(
n_estimators=400,
max_depth=6,
learning_rate=0.05,
objective="reg:squarederror",
tree_method="hist",
random_state=42,
)),
])
pipe.fit(X_train, y_train)
predicciones_semana = pipe.predict(X_test)
Combinado con la ingeniería de features temporales (lag-1, lag-7, media movil 4 semanas, festivos codificados) este patrón cubre el 80% de los problemas de forecasting de demanda en retail, logistica y fabricación.
Con este patrón dispones de una comparativa rápida y fiable entre la opción nativa de Scikit-learn y las tres librerías externas, y sabes cuándo aplicar cada una en proyectos reales de fraude, scoring, churn y forecasting.
Alan Sastre
Ingeniero de Software y formador, CEO en CertiDevs
Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, Scikit Learn es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.
Más tutoriales de Scikit Learn
Explora más contenido relacionado con Scikit Learn y continúa aprendiendo con nuestros tutoriales gratuitos.
Aprendizajes de esta lección
Instalar y usar XGBoost, LightGBM y CatBoost con la API compatible de Scikit-learn. Elegir entre HistGradientBoosting nativo y las librerías externas según el caso. Integrar cualquiera de ellos como estimador final en un Pipeline de Scikit-learn. Ajustar hiperparámetros clave de cada implementación.