Pipelines
La Pipeline de sklearn encadena pasos de preprocesamiento y estimadores en un único objeto que se ajusta, predice y serializa conjuntamente. Las pipelines son la forma estándar de mantener el entrenamiento y la inferencia reproducibles y sin fugas.
Receta
Tarjeta de referencia rápida - lista para copiar y pegar.
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
pipe = Pipeline([
("scaler", StandardScaler()),
("clf", LogisticRegression(max_iter=1000)),
])
pipe.fit(X_train, y_train)
preds = pipe.predict(X_test)Cuándo usar esto:
- Cualquier proyecto con preprocesamiento más un modelo (escalado, codificación, imputación).
- Validación cruzada o búsqueda de cuadrícula donde las transformaciones deben reajustarse por pliegue.
- Despliegue de modelos donde la inferencia debe aplicar el mismo preprocesamiento que el entrenamiento.
- Combinación de múltiples ramas de transformación con
FeatureUnion.
Ejemplo de Trabajo
"""pipelines.py - pipeline de extremo a extremo con ColumnTransformer y búsqueda de cuadrícula."""
from __future__ import annotations
import joblib
import pandas as pd
from sklearn.compose import ColumnTransformer
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import f1_score
from sklearn.model_selection import GridSearchCV, train_test_split
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder, StandardScaler
df = pd.read_csv("customers.csv") # columnas: age, tenure, region, plan, churned
X = df.drop(columns=["churned"])
y = df["churned"]
num_cols, cat_cols = ["age", "tenure"], ["region", "plan"]
preprocessor = ColumnTransformer([
("num", StandardScaler(), num_cols),
("cat", OneHotEncoder(handle_unknown="ignore"), cat_cols),
])
pipe = Pipeline([
("prep", preprocessor),
("clf", RandomForestClassifier(random_state=42)),
])
param_grid = {
"clf__n_estimators": [100, 200],
"clf__max_depth": [None, 10],
}
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, stratify=y, random_state=42)
search = GridSearchCV(pipe, param_grid, cv=5, scoring="f1")
search.fit(X_train, y_train)
best = search.best_estimator_
print("mejores parámetros:", search.best_params_)
print("F1 de prueba:", f1_score(y_test, best.predict(X_test)))
joblib.dump(best, "churn_pipeline.joblib")Lo que esto demuestra:
- Preprocesamiento y clasificador como un único objeto estimable.
- Búsqueda de hiperparámetros con parámetros prefijados por el paso (
clf__n_estimators). - La CV reajusta el preprocesador automáticamente dentro de cada pliegue.
- Pipeline completa persistida para un preprocesamiento de inferencia idéntico.
Inmersión Profunda
Cómo Funciona
- Cada paso es una tupla
(nombre, transformador); el último paso debe ser un estimador. fitllama afit_transformen los pasos intermedios y afiten el último paso.predictejecutatransforma través de todos los pasos excepto el último, luegopredict.Pipelineimplementa la interfaz de estimador de sklearn - funciona con CV, búsqueda de cuadrícula y ensembles.- Las pipelines anidadas (por ejemplo, una sub-pipeline numérica dentro de
ColumnTransformer) se componen limpiamente.
Pipeline vs Pasos Manuales
| Enfoque | Riesgo de Fuga | Despliegue | Compatible con CV |
|---|---|---|---|
| Ajuste/transformación manual | Alto | Propenso a errores | No |
Pipeline | Bajo | Artefacto único | Sí |
| Celdas de Notebook | Alto | No reproducible | No |
Notas de Python
from sklearn.pipeline import FeatureUnion
combined = FeatureUnion([
("pca", PCA(n_components=10)),
("raw", "passthrough"),
])
pipe = Pipeline([("features", combined), ("clf", SVC())])
# Acceder a los pasos por nombre
pipe.named_steps["clf"].feature_importances_Trampas
- Olvidar incluir el preprocesamiento en la pipeline -
scaler.fit(X_train)manual y luegomodel.fit(X_train_scaled)rompe bajo CV. Solución: envolver ambos enPipeline. - Prefijo de parámetro de paso incorrecto -
n_estimatorsen lugar declf__n_estimatorsen la búsqueda de cuadrícula ignora silenciosamente los parámetros. Solución: usarpipe.get_params().keys()para verificar los nombres. - Guardar solo el modelo - cargar un clasificador desnudo sin el escalador produce predicciones incorrectas. Solución:
joblib.dump(pipe, ...)la pipeline completa. - Valor por defecto mutable en
FunctionTransformer- las lambdas y cierres pueden no serializarse. Solución: usar funciones a nivel de módulo osklearn.preprocessing.FunctionTransformer. - Último paso no es un estimador - las pipelines que terminan en un transformador no pueden
predict. Solución: terminar con un clasificador/regresor o usarTransformedTargetRegressor. - Desajuste de orden de columnas en la inferencia - columnas de pandas reordenadas entre entrenamiento y servicio. Solución: forzar el orden de las columnas con
X[expected_cols]antes depredict.
Alternativas
| Alternativa | Usar Cuando | No Usar Cuando |
|---|---|---|
Pipeline | Flujos de trabajo estándar de sklearn | Bucles personalizados de aprendizaje profundo (usar módulos de PyTorch) |
imblearn.pipeline.Pipeline | Remuestreo dentro de CV | Sin desequilibrio de clases |
fit/transform manual de sklearn | Enseñanza/depuración de un paso | Flujos de trabajo de producción o CV |
sklearn.set_output(transform="pandas") | Necesidad de salida DataFrame de las transformaciones | Salida puramente numpy posterior |
Preguntas Frecuentes
¿Por qué no puedo simplemente escalar los datos una vez antes de la CV?
- El escalado global utiliza estadísticas de las filas del pliegue de validación.
- La pipeline reajusta el escalador solo en cada pliegue de entrenamiento.
- Esta es la fuente más común de puntuaciones de CV infladas.
¿Cómo accedo al modelo ajustado dentro de una pipeline?
fitted_clf = pipe.named_steps["clf"]
importances = fitted_clf.feature_importances_named_stepses un diccionario con claves por nombre de paso.
¿Pueden las pipelines manejar pesos de muestra?
- Pase
pipe.fit(X, y, clf__sample_weight=weights). - El prefijo coincide con el nombre del paso del estimador.
- No todos los transformadores admiten pesos de muestra.
¿Cómo añado pasos de transformación personalizados?
from sklearn.base import BaseEstimator, TransformerMixin
class Log1pTransformer(BaseEstimator, TransformerMixin):
def fit(self, X, y=None):
return self
def transform(self, X):
import numpy as np
return np.log1p(X)- Heredar
BaseEstimator, TransformerMixinpara compatibilidad con sklearn.
¿Qué es FeatureUnion?
- Ejecuta múltiples transformaciones en paralelo y concatena las salidas.
- Útil para combinar características de texto TF-IDF con características numéricas.
- Diferente de
ColumnTransformer, que selecciona columnas por rama.
¿Cómo depuro un paso de pipeline?
Xt = pipe.named_steps["prep"].transform(X_train[:5])
print(Xt.shape, Xt[:2])- Inspeccionar la salida intermedia llamando a
transformen pasos individuales después de ajustarlos.
¿Funciona Pipeline con DataFrames de pandas?
- Sí, cuando los transformadores aceptan DataFrames (
ColumnTransformer, versiones recientes de sklearn). - Establezca
transform_output="pandas"enColumnTransformerpara columnas con nombre.
¿Cómo versiono los artefactos de la pipeline?
- Guardar con
joblib.dumpincluyendo metadatos JSON (fecha de entrenamiento, hash de datos, métricas). - Registrar en MLflow o en un registro de modelos para flujos de trabajo de promoción.
- Ver Seguimiento de Experimentos.
¿Puedo usar pipelines con XGBoost o LightGBM?
- Sí - envuelva
xgboost.XGBClassifiercomo el paso final de la pipeline. - Los pasos de preprocesamiento siguen siendo transformadores de sklearn.
- Use la pipeline de
imblearnsi combina con SMOTE.
¿Qué pasa con la transformación del objetivo?
from sklearn.compose import TransformedTargetRegressor
model = TransformedTargetRegressor(regressor=pipe, func=np.log1p, inverse_func=np.expm1)- Transformar logarítmicamente objetivos sesgados manteniendo las predicciones en la escala original.
¿Cómo excluyo un paso durante la predicción?
- Use
Pipeline(memory=...)para almacenar en caché transformaciones costosas durante la búsqueda de cuadrícula. - Para pasos condicionales, considere pipelines separadas por caso de uso.
¿Cómo interactúan las pipelines con la exportación ONNX?
- Las pipelines de sklearn se convierten a través de
skl2onnxcuando todos los pasos son compatibles. - Los transformadores personalizados complejos pueden bloquear la conversión - pruebe temprano.
Relacionado
- Ingeniería de Características - Patrones de
ColumnTransformer - Conjuntos de Datos y Divisiones - CV con pipelines
- Ajuste de Hiperparámetros - prefijos de parámetros de búsqueda de cuadrícula
- Servicio con FastAPI - carga de artefactos de pipeline
- Mejores Prácticas de Machine Learning - reglas de reproducibilidad
Versiones de Stack: Esta página fue escrita para Python 3.14.0 (estable 3.14, mantenimiento 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, y uv 0.6+.