← Todo el material
Curso Intermedio 23 de agosto de 2026

Machine Learning — Módulo 8: feature engineering y pipelines — donde se gana de verdad

Octavo módulo del Curso de Machine Learning: encoding de categóricas (one-hot y target encoding), escalado, imputación de faltantes y creación de features, más Pipeline y ColumnTransformer de scikit-learn para evitar el data leakage. Con código real.

☰ Índice del contenido

En el Módulo 7 llegamos a XGBoost, el modelo que gana competencias. Y sin embargo, si le entregas datos crudos, hasta el mejor modelo del mundo rinde mediocre. Aquí viene el secreto peor guardado del machine learning aplicado: la mayor parte del resultado se juega antes del modelo, en cómo preparas los datos. Un XGBoost con buenas features le gana a un XGBoost con features malas por mucho más de lo que le ganarías cambiando de algoritmo. Este módulo cierra el bloque intermedio con lo que de verdad mueve la aguja — el feature engineering — y con la herramienta que lo hace seguro y reproducible: los pipelines de scikit-learn.

La tesis del módulo

El modelo es el 20%; los datos que le das son el 80%. El feature engineering es transformar datos crudos en variables que el modelo pueda aprovechar. Y un pipeline no es una comodidad: es la garantía de que apliques exactamente el mismo preprocesamiento en train y en producción, sin filtrar información del futuro.

Los datos crudos rara vez sirven directos

Una tabla real llega sucia: columnas de texto que el modelo no entiende, números en escalas disparatadas, celdas vacías. Antes de entrenar hay que arreglar todo eso. Vamos por las cuatro operaciones básicas.

1. Encoding de variables categóricas

Los modelos comen números, no texto. Una columna como ciudad con valores “Santiago”, “Valparaíso”, “Concepción” hay que convertirla. Dos formas:

  • One-hot encoding (glosamos: crear una columna nueva por cada categoría, con un 1 si la fila es de esa categoría y 0 si no). “ciudad” se vuelve tres columnas: ciudad_Santiago, ciudad_Valparaíso, ciudad_Concepción. Simple y sin inventar orden falso, pero explota en columnas si hay muchas categorías (alta cardinalidad).
  • Target encoding (glosamos: reemplazar cada categoría por el promedio del objetivo para esa categoría — por ejemplo, la tasa de fraude histórica de cada ciudad). Compacto y potente con muchas categorías, pero peligroso: si lo calculas mal, filtras la respuesta y provocas leakage. El TargetEncoder de scikit-learn (desde la 1.3) lo hace bien por defecto: su fit_transform usa cross fitting interno, así que cada fila se codifica con promedios calculados sin ella.

2. Escalado de variables numéricas

Si una variable va de 0 a 1 y otra de 0 a 1.000.000, algunos modelos (regresión, redes) le dan un peso desproporcionado a la grande solo por su magnitud. El escalado las pone en rangos comparables. El más común es StandardScaler, que deja cada variable con media 0 y desviación 1. (Recuerda del módulo 5: los árboles y ensembles no necesitan escalado; la regresión y las redes sí.)

3. Imputación de faltantes

Casi ningún modelo tolera celdas vacías. Imputar es rellenarlas con un valor razonable: la media o la mediana para números, la categoría más frecuente para texto. En scikit-learn: SimpleImputer.

4. Crear features nuevas

Aquí está el arte, y donde un humano que entiende el problema le gana a cualquier automatismo. Ejemplos:

  • De una fecha, extraer día de la semana, mes, si es feriado, cuántos días faltan para el evento.
  • Ratios: en vez de “deuda” e “ingreso” por separado, crear deuda / ingreso, que suele ser mucho más predictivo.
  • Agregaciones: por cada cliente, su gasto promedio, su número de compras, días desde la última.
TécnicaHerramientaCuándo usarla
One-hot encodingOneHotEncoderCategóricas con pocas categorías
Target encodingTargetEncoderCategóricas de alta cardinalidad
EscaladoStandardScalerRegresión, redes (no árboles)
ImputaciónSimpleImputerCualquier columna con faltantes
Ratios y fechasCódigo propioCasi siempre: donde más se gana

Pipeline: encadenar todo en un solo objeto

El problema práctico: son muchos pasos, y tienes que aplicar exactamente los mismos al entrenar, al validar y en producción con cada dato nuevo. Hacerlo a mano es una fuente infinita de bugs. La solución de scikit-learn es el Pipeline (glosamos: un objeto que encadena varios pasos de preprocesamiento y el modelo final en una sola unidad, de modo que fit y predict recorren todos los pasos en orden).

Como distintas columnas necesitan distinto trato (las numéricas se escalan, las categóricas se codifican), se combina con el ColumnTransformer (glosamos: aplica transformaciones diferentes a grupos de columnas distintos, en paralelo, y junta el resultado). Numéricas por un carril, categóricas por otro, todo dentro del mismo pipeline.

      features crudas (tabla con texto,
      números y celdas vacías)
                 │
                 ▼
     ┌───────────────────────┐
     │   ColumnTransformer   │
     └───────────┬───────────┘
                 │
        ┌────────┴────────┐
        ▼                 ▼
 ┌─────────────┐   ┌──────────────┐
 │ numéricas:  │   │ categóricas: │
 │ imputar +   │   │ imputar +    │
 │ escalar     │   │ one-hot      │
 └──────┬──────┘   └──────┬───────┘
        │                 │
        └────────┬────────┘
                 ▼
        ┌─────────────────┐
        │  modelo (XGB)   │
        └────────┬────────┘
                 ▼
            PREDICCIÓN

El pipeline en código

Todo encapsulado: fit sobre train aprende las transformaciones y entrena el modelo; predict sobre datos nuevos aplica lo mismo.

from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.impute import SimpleImputer
from sklearn.ensemble import RandomForestClassifier

# qué columnas son de cada tipo (según tu tabla)
num_cols = ["edad", "ingreso", "deuda"]
cat_cols = ["ciudad", "profesion"]

# carril numérico: rellenar faltantes con la mediana, luego escalar
num_pipe = Pipeline([
    ("imputar", SimpleImputer(strategy="median")),
    ("escalar", StandardScaler()),
])

# carril categórico: rellenar con la moda, luego one-hot
cat_pipe = Pipeline([
    ("imputar", SimpleImputer(strategy="most_frequent")),
    ("onehot", OneHotEncoder(handle_unknown="ignore")),
])

# ColumnTransformer: cada carril a sus columnas
preproceso = ColumnTransformer([
    ("num", num_pipe, num_cols),
    ("cat", cat_pipe, cat_cols),
])

# pipeline completo: preprocesamiento + modelo, en UN objeto
modelo = Pipeline([
    ("preproceso", preproceso),
    ("clf", RandomForestClassifier(n_estimators=300, random_state=42)),
])

# un solo fit: aprende TODO sobre train (imputadores, escalador, modelo)
modelo.fit(X_train, y_train)

# un solo predict: aplica exactamente lo mismo a datos nuevos
pred = modelo.predict(X_test)

Fíjate en handle_unknown="ignore": si en producción aparece una ciudad que no estaba en train, no explota. Esos detalles son los que separan un notebook de un modelo que sobrevive en producción — el tema del módulo 12.

Data leakage: el enemigo silencioso

El data leakage (glosamos: filtrar hacia el entrenamiento información que en el momento real de predecir no tendrías — datos del conjunto de test, o información del futuro) es el error más traicionero del machine learning, porque no da la cara: tu modelo muestra métricas espectaculares en el notebook y luego fracasa en producción.

El caso clásico: escalas o imputas usando todo el dataset (train + test juntos) antes de separar. Al hacerlo, la media que usa el escalador ya “vio” el test. Tu evaluación queda contaminada y optimista.

Aquí está la razón profunda de usar pipelines: cuando el escalador o el imputador van dentro del pipeline, el fit corre solo sobre train. La media, la mediana, las categorías del one-hot — todo se aprende exclusivamente del entrenamiento, y luego se aplica al test. El leakage se vuelve casi imposible por construcción.

 MAL (leakage)              BIEN (pipeline)

┌────────────────────┐     ┌────────────────────┐
│ escalar TODO el    │     │ separar train/test │
│ dataset            │     │ ANTES de nada      │
└─────────┬──────────┘     └─────────┬──────────┘
          ▼                          ▼
┌────────────────────┐     ┌────────────────────┐
│ separar train/test │     │ fit escala SOLO    │
│ (¡ya es tarde!)    │     │ sobre train        │
└─────────┬──────────┘     └─────────┬──────────┘
          ▼                          ▼
┌────────────────────┐     ┌────────────────────┐
│ el test influyó    │     │ el test nunca      │
│ en la media  (X)   │     │ influyó  (OK)      │
└────────────────────┘     └────────────────────┘

Ojo: el leakage no es solo del test. También lo cometes si usas una variable que en producción no existiría al momento de predecir (por ejemplo, “monto reembolsado” para predecir si una compra será fraude — ese dato llega después). Pregúntate siempre: ¿tendría este dato en el instante real de la predicción?

Errores comunes

  • Escalar o imputar antes de separar train/test. Es el leakage clásico. Mete esos pasos dentro del pipeline para que el fit corra solo sobre train.
  • Target encoding calculado a mano sobre todo el dataset. Filtra el objetivo directo. Usa TargetEncoder (que hace cross fitting solo) dentro del pipeline, o al menos calcúlalo con validación cruzada.
  • Escalar antes de un árbol o un ensemble. Trabajo inútil: no lo necesitan (módulos 5 y 6).
  • Olvidar handle_unknown="ignore" en el one-hot. En producción aparecerá una categoría nueva y el modelo caerá.
  • Creer que cambiar de modelo es donde se gana. La mayoría de las veces se gana en las features, no en el algoritmo. XGBoost con features malas pierde contra un modelo simple con features buenas.

La frase para llevarse

“El modelo es el 20%; los datos, el 80%. Y el pipeline no es comodidad: es lo que impide que el futuro se filtre en tu entrenamiento y te mienta con métricas hermosas.”

Qué viene

Con esto cierra el bloque intermedio: ya sabes elegir modelos y, más importante, prepararles los datos sin filtrar información. Pero queda una pregunta grande: ¿cómo sabes que tu evaluación es de fiar, y cómo encuentras los mejores hiperparámetros sin adivinar? En el Módulo 9: validación y tuning veremos la validación cruzada (cross-validation) para medir de verdad, y la búsqueda de hiperparámetros (grid search, random search) para exprimir cada modelo — todo, por supuesto, envuelto en el pipeline que acabas de aprender.

Material relacionado

Machine Learningscikit-learnFeature engineeringPipelinesData leakage

Preguntas sobre este curso

Regístrate gratis para hacer preguntas y guardar tu progreso.

✉ Entérate de lo nuevo

Recibe un aviso cuando publique nuevos cursos, workshops o investigaciones. Sin spam.