19. Pipelines: automatizar pasos en Scikit-learn

19.1 El problema de hacer pasos sueltos

En Machine Learning rara vez alcanza con entrenar un modelo directamente sobre los datos originales. Antes suelen aparecer tareas como:

  • rellenar valores faltantes;
  • escalar variables;
  • codificar columnas categóricas;
  • entrenar el modelo final.

Si hacemos esos pasos por separado y a mano, es fácil cometer errores. Por ejemplo, podríamos transformar el conjunto de entrenamiento de una forma y olvidarnos de aplicar exactamente lo mismo a los datos nuevos.

19.2 Qué es un Pipeline

Un Pipeline en Scikit-learn es una forma de encadenar varios pasos en un único flujo ordenado.

La idea es simple:

  • primero se aplica el preprocesamiento;
  • después se entrena el modelo;
  • cuando llega un dato nuevo, se repiten automáticamente los mismos pasos.

Eso hace que el flujo sea más seguro, más claro y más fácil de mantener.

19.3 Por qué Pipeline es tan importante

Pipeline no es solo una comodidad de sintaxis. Es una herramienta para reducir errores conceptuales y prácticos.

Sus principales ventajas son:

  • evita inconsistencias entre entrenamiento y predicción;
  • mantiene todo el flujo en un solo objeto;
  • se combina muy bien con validación cruzada y búsqueda de hiperparámetros;
  • hace que el código sea más reproducible.

19.4 Un ejemplo típico del mundo real

Supongamos que queremos predecir si un estudiante aprobará. Tenemos variables como:

  • horas de estudio;
  • cantidad de prácticas;
  • asistencia.

Pero el dataset tiene valores faltantes y, además, queremos escalar las variables antes de usar regresión logística.

Este es un caso ideal para un Pipeline.

19.5 Ejemplo muy claro: imputar, escalar y clasificar

import pandas as pd
from sklearn.impute import SimpleImputer
from sklearn.model_selection import train_test_split
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score

datos = pd.DataFrame({
    "horas_estudio": [2, 3, 4, None, 6, 7, 8, 9, 10, None],
    "practicas": [1, 2, None, 3, 4, 5, 5, 6, None, 7],
    "asistencia": [60, 65, 70, 72, None, 80, 85, 90, 95, 88],
    "aprobo": [0, 0, 0, 0, 1, 1, 1, 1, 1, 1]
})

X = datos[["horas_estudio", "practicas", "asistencia"]]
y = datos["aprobo"]

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.3, random_state=42, stratify=y
)

modelo = Pipeline([
    ("imputador", SimpleImputer(strategy="median")),
    ("escalador", StandardScaler()),
    ("clasificador", LogisticRegression(max_iter=1000))
])

modelo.fit(X_train, y_train)

y_pred = modelo.predict(X_test)
print("Valores reales:", y_test.values)
print("Predicciones:", y_pred)
print("Exactitud:", accuracy_score(y_test, y_pred))

nuevo_estudiante = pd.DataFrame({
    "horas_estudio": [5],
    "practicas": [4],
    "asistencia": [78]
})

prediccion = modelo.predict(nuevo_estudiante)[0]
probabilidad = modelo.predict_proba(nuevo_estudiante)[0, 1]

print("Predicción para el nuevo estudiante:", prediccion)
print(f"Probabilidad de aprobar: {probabilidad:.3f}")

Salida resumida esperada:

Valores reales: [...]
Predicciones: [...]
Exactitud: ...
Predicción para el nuevo estudiante: ...
Probabilidad de aprobar: ...

19.6 Qué está pasando en el ejemplo

El flujo completo se ejecuta dentro de un único objeto llamado modelo. Cuando entrenamos:

  • primero se imputan los valores faltantes;
  • después se escalan las variables;
  • al final se ajusta la regresión logística.

Cuando llega un caso nuevo, el pipeline repite exactamente las mismas transformaciones antes de predecir.

19.7 Explicación detallada de cada paso

  • SimpleImputer(strategy="median"): rellena valores faltantes con la mediana de cada columna.
  • StandardScaler(): pone las variables en una escala comparable.
  • LogisticRegression(max_iter=1000): entrena el clasificador final.
  • Pipeline([...]): une todo en una secuencia ordenada.

El resultado práctico es que ya no necesitamos recordar manualmente qué transformación aplicar en cada momento.

19.8 Por qué Pipeline evita fuga de información

Uno de los riesgos clásicos en Machine Learning es la fuga de información: usar datos del conjunto de prueba al preparar el entrenamiento.

Pipeline ayuda a evitar ese problema porque, cuando se usa correctamente junto con separación de datos o validación cruzada, cada transformación se ajusta solo con la información correspondiente al entrenamiento de esa iteración.

19.9 Pipeline y validación cruzada combinan muy bien

Una gran ventaja de Pipeline es que se integra naturalmente con herramientas como:

  • cross_val_score;
  • GridSearchCV;
  • RandomizedSearchCV.

Eso permite evaluar o ajustar el flujo completo, no solo el modelo aislado.

19.10 Errores frecuentes

  • Preprocesar fuera del Pipeline y luego olvidar replicarlo: genera inconsistencias.
  • Escalar antes de separar entrenamiento y prueba: puede introducir fuga de información.
  • Creer que Pipeline es solo estética: en realidad mejora la calidad técnica del flujo.
  • No usar nombres claros en los pasos: conviene que cada etapa se entienda fácilmente.

19.11 Qué deberías retener

  • Pipeline permite encadenar preprocesamiento y modelo en un solo flujo.
  • Reduce errores y hace el código más reproducible.
  • Garantiza que los mismos pasos se apliquen al entrenar y al predecir.
  • Es especialmente útil cuando hay imputación, escalado o codificación.
  • Se integra muy bien con validación cruzada y ajuste de hiperparámetros.