Módulo / 3. Fundamentos de ML
0%
Módulo 3 · Core

Fundamentos de ML

Aquí pasamos de las herramientas matemáticas al ciclo completo de aprendizaje: datos, hipótesis, pérdida, optimización y generalización. Estos conceptos son más importantes que cualquier algoritmo concreto: sobreviven a todas las modas.

7 lecciones 14 h estimadas Simulador de overfitting
0 de 7 lecciones completadas
Lección 3.1

¿Cómo aprende una máquina?

18 minConceptual + formalBucle de entrenamiento

Aprender, en ML, es ajustar los parámetros de una función para que cometa menos errores sobre datos que no ha visto. Todo el proceso se reduce a cuatro piezas: datos, modelo, pérdida y optimizador.

Las cuatro piezas

1

Datos

Una muestra de ejemplos $(x_i,y_i)$ que representa el problema. Sin datos representativos, no hay aprendizaje posible.

2

Modelo

Una familia de funciones $f_\theta$ con parámetros $\theta$. La arquitectura define qué formas puede representar.

3

Pérdida

Una medida $L(y,f_\theta(x))$ de cuán mal predice el modelo. Convierte el objetivo en un número que se puede minimizar.

4

Optimizador

Un procedimiento que actualiza $\theta$ para reducir la pérdida: descenso del gradiente, mínimos cuadrados, Adam…

El problema de aprendizaje, formalmente

Sea $\mathcal{H}$ el espacio de hipótesis (todas las funciones que nuestro modelo puede representar). Buscamos:

Riesgo empírico $$\hat{\theta} = \arg\min_{\theta} \; \hat{R}(\theta) = \arg\min_{\theta} \; \frac{1}{n}\sum_{i=1}^{n} L\left(y_i, f_\theta(x_i)\right)$$ $\hat{R}$ es el riesgo empírico: el error promedio en la muestra. El verdadero objetivo es minimizar el riesgo esperado sobre la distribución $\mathcal{D}$, que no conocemos.

Esta distinción es el corazón del ML: minimizar el error de entrenamiento es fácil (basta memorizar); lo difícil es generalizar. Todo el Módulo 3 gira alrededor de esa tensión.

El bucle de entrenamiento

Pythontraining_loop.py
# Pseudocódigo del bucle universal de entrenamiento
for epoca in range(num_epocas):
    for batch in data_loader:
        X, y = batch
        y_pred = modelo(X)                 # forward pass
        loss = perdida(y, y_pred)          # calcular error
        gradientes = calcular_gradiente(loss, parametros)  # backprop
        parametros -= learning_rate * gradientes           # actualizar
    validar(modelo, validacion)            # medir generalización

Este esqueleto es el mismo para una regresión logística, una CNN o un Transformer. Cambian el modelo, la pérdida y el optimizador; el ciclo es idéntico.

Una analogía útil: el tiro con arco

El modelo es el arco; los parámetros, la tensión y el ángulo; la pérdida, la distancia al centro; el optimizador, el ajuste tras cada flecha. Con una sola flecha no puedes calibrar; con muchas, corriges. Pero si solo practicas a una distancia fija, fallarás en otra: eso es overfitting.

Tipos de aprendizaje, otra vez

Señal disponibleObjetivoEjemplo
Etiquetas $y$Predecir $y$Supervisado: regresión/clasificación
Solo $x$EstructuraNo supervisado: clustering, PCA
RecompensaPolítica óptimaRefuerzo: juegos, robótica
Datos + pocas etiquetasPredecir con bajo costo de etiquetadoSemi-supervisado
El propio datoRepresentaciónAuto-supervisado: LLMs, contrastivo
No todo es gradient descent Los árboles se construyen con búsqueda codiciosa de divisiones; K-Means alterna asignaciones y centroides; los KNN no tienen entrenamiento. El marco «modelo + pérdida + optimizador» sigue aplicando, aunque el optimizador no sea un gradiente.
Ejercicio 3.1 · Descomponer un problema

Para predecir el precio de una vivienda, define: (a) los datos y la forma de cada ejemplo; (b) el espacio de hipótesis si usas una regresión lineal; (c) la pérdida; (d) el optimizador; (e) cómo medirás la generalización.

Orientación: (a) vector de features (superficie, habitaciones, distrito) y etiqueta continua; (b) $f_\theta(x)=w^\top x+b$; (c) MSE; (d) mínimos cuadrados o descenso del gradiente; (e) RMSE sobre un conjunto de prueba no utilizado durante el ajuste.

Lección 3.2

Datos, features y labels

17 minDatosDatasets públicos

Un dataset es una tabla (o colección de archivos) donde cada fila es un ejemplo, cada columna una característica y, en aprendizaje supervisado, una columna especial es la etiqueta que queremos predecir.

Matriz de diseño y vector objetivo $$X\in\mathbb{R}^{n\times d}, \qquad \mathbf{y}\in\mathcal{Y}^n$$ $n$ ejemplos, $d$ features. $x_{ij}$ es el valor de la feature $j$ para el ejemplo $i$.

Tipos de variables

TipoEjemplosTratamiento
Numérica continuaTemperatura, ingreso, precioEstandarizar, transformar, discretizar si aporta
Numérica discretaNúmero de hijos, clicsTratar como numérica o categórica según cardinalidad
Categórica nominalCiudad, color, marcaOne-hot, target encoding, embeddings
Categórica ordinalNivel educativo, riesgoCodificación ordinal respetando el orden
TextoReseñas, correosTF-IDF, embeddings, transformers
ImagenRadiografías, fotosNormalización, aumentación, CNN
Serie temporalPrecio diario, sensoresLags, ventanas, validación temporal

Datasets públicos que usaremos

DatasetTareaTamañoDónde
IrisClasificación multiclase150 × 4sklearn.datasets
California HousingRegresión20 640 × 8sklearn.datasets
TitanicClasificación binaria891 × 11Kaggle
20 NewsgroupsClasificación de texto≈18 000 documentossklearn.datasets
SMS Spam CollectionClasificación de texto5 574 mensajesUCI ML Repository
MNIST / Fashion-MNISTClasificación de imágenes70 000 imágenes 28×28keras.datasets
CIFAR-10Clasificación de imágenes60 000 imágenes 32×32Toronto
IMDBAnálisis de sentimiento50 000 reseñasHugging Face / Keras
MovieLensRecomendación100k–25M ratingsGroupLens
Credit Card FraudDetección de fraude284 807 × 30Kaggle / OpenML

Calidad de datos: lo que mata proyectos

  • Valores faltantes: ¿faltan al azar o sistemáticamente? Si faltan más en un grupo, imputar la media puede introducir sesgo.
  • Duplicados: inflan el rendimiento si caen en train y test. Elimínalos antes de dividir.
  • Outliers: pueden ser errores o señal. Investiga antes de recortar.
  • Etiquetas ruidosas: un 5% de etiquetas mal puestas limita el techo de cualquier modelo.
  • Desbalance: si una clase es el 1%, accuracy no sirve como métrica.
  • Sesgo de selección: los datos reflejan cómo se recogieron, no necesariamente la población objetivo.
La regla de oro Un modelo mediocre con datos excelentes suele superar a un modelo excelente con datos malos. La mayor parte del trabajo real de ML es entender y curar datos, no elegir arquitecturas.

Cargar y dividir con Scikit-learn

Pythondatos.py
from sklearn.datasets import load_iris, fetch_california_housing
from sklearn.model_selection import train_test_split

iris = load_iris(as_frame=True)
X, y = iris.data, iris.target
print(X.shape, y.shape)
print(iris.target_names)

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)
print("train:", X_train.shape, "test:", X_test.shape)

# Regresión: sin estratificar
housing = fetch_california_housing(as_frame=True)
Xh, yh = housing.data, housing.target
Xtr, Xte, ytr, yte = train_test_split(Xh, yh, test_size=0.2, random_state=42)
Ejercicio 3.2 · Auditoría de un dataset

Elige un dataset público y responde: ¿cuántas filas y columnas? ¿cuál es la etiqueta y de qué tipo? ¿hay nulos, duplicados o desbalance? ¿qué representa una fila? ¿qué riesgo de sesgo ves? Documenta tus hallazgos en una tabla antes de entrenar cualquier modelo.

Lección 3.3

Train, validation, test y fuga de información

20 minMetodologíaErrores críticos

No puedes evaluar un modelo con los mismos datos con los que lo entrenaste. La separación de conjuntos es la garantía mínima de que estás midiendo generalización y no memorización.

Los tres conjuntos

ConjuntoProporción típicaUsoQué no hacer
Train60–80%Ajustar parámetrosNo evaluar rendimiento final
Validation10–20%Elegir modelo e hiperparámetrosNo usarlo para el ajuste de parámetros
Test10–20%Estimar rendimiento final una vezNo mirarlo repetidamente para decidir

Si el dataset es pequeño, la validación cruzada ($k$-fold) use el train completo para estimar el rendimiento y reserva el test para el final. Lo veremos en el Módulo 6.

Fuga de información (data leakage)

Ocurre cuando información del conjunto de validación o test se filtra al entrenamiento. Es la causa más común de resultados «demasiado buenos» que se desmoronan en producción.

Ejemplo clásico Estandarizas todo el dataset y después lo divides. La media y la desviación usadas para escalar el train incluyen información del test. La fuga es sutil, pero infla la métrica. Regla: divide primero, ajusta el preprocesamiento solo con train.
FugaCómo se cuelaSolución
Escalado antes de dividirEstadísticas globalesPipeline que ajusta solo en train
Target encoding sin CVLa media de $y$ incluye la filaEncoding out-of-fold
Duplicados entre splitsEl mismo ejemplo en train y testDeduplicar antes de dividir
Features del futuroDatos posteriores al eventoValidación temporal, revisar disponibilidad
Selección de features con todo el datasetEl test influye en qué variables se eligenSelección dentro del fold de train
Ajuste de hiperparámetros en testEliges el mejor de 100 en el mismo testValidación separada o anidada

Divisiones especiales

Estratificada

Mantiene la proporción de clases en cada split. Indispensable con desbalance. stratify=y.

Temporal

Train con el pasado, test con el futuro. Nunca aleatorizar series temporales: rompe la causalidad y produce fugas.

Por grupo

Si hay varias filas por paciente o usuario, todos sus registros deben ir al mismo split. Evita que el modelo reconozca individuos.

Validación cruzada

Cuando hay pocos datos: $k$ particiones, se entrena $k$ veces y se promedian las métricas. Más robusta que un solo split.

Pythonsplits.py
from sklearn.model_selection import (
    train_test_split, StratifiedKFold, TimeSeriesSplit, GroupKFold
)

# 1) Split estratificado (clasificación desbalanceada)
X_tr, X_te, y_tr, y_te = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)

# 2) Validación cruzada estratificada
skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
for fold, (tr_idx, va_idx) in enumerate(skf.split(X, y), 1):
    print(f"fold {fold}: train={len(tr_idx)}, val={len(va_idx)}")

# 3) Serie temporal: nunca mezclar pasado y futuro
tscv = TimeSeriesSplit(n_splits=5)

# 4) Por grupo (mismo paciente no se reparte entre splits)
# gkf = GroupKFold(n_splits=5)
# for tr, va in gkf.split(X, y, groups=patient_id):
#     ...

# 5) Test final: se toca una sola vez
# metricas_finales = evaluar(modelo_final, X_te, y_te)
Regla práctica Si tu métrica de test es sospechosamente alta, busca una fuga antes de celebrar. Pregunta: ¿alguna feature se calcula después del evento? ¿el mismo ejemplo aparece dos veces? ¿el preprocesamiento vio el test?
Ejercicio 3.3 · Detectar fugas

Un modelo predice si un cliente cancelará su suscripción con accuracy 0.99. Entre las features están «número de llamadas al servicio de cancelación» y «fecha de baja». ¿Qué está mal?

Respuesta: ambas features se conocen solo después (o durante) la cancelación. Son consecuencias de la etiqueta, no predictores disponibles en el momento de la decisión. El modelo aprende a detectar el evento ya ocurrido. La solución es usar solo información disponible antes del periodo de predicción y validar temporalmente.

Lección 3.4

Modelos, parámetros e hiperparámetros

16 minConceptualCapacidad

Parámetros vs. hiperparámetros

ParámetrosHiperparámetros
Se aprendenSí, durante el entrenamientoNo, se eligen antes
EjemplosPesos $w$, sesgos $b$, centroidesTasa de aprendizaje, $k$ en KNN, profundidad de árbol
Cómo se fijanOptimizaciónValidación cruzada, búsqueda
ImpactoDefinen la función ajustadaDefinen la capacidad y el proceso de aprendizaje

Capacidad del modelo

La capacidad es la complejidad de las funciones que un modelo puede representar. Un polinomio de grado 1 tiene capacidad baja; uno de grado 20, alta. Una red con millones de pesos, altísima.

Compromiso capacidad–generalización $$\text{Error total} = \text{Error de aproximación (bias)} + \text{Error de estimación (variance)} + \text{Ruido}$$ Demasiada capacidad → overfitting. Demasiada poca → underfitting. El objetivo es el punto de equilibrio para tu tamaño de datos.

Modelos paramétricos y no paramétricos

  • Paramétricos: tienen un número fijo de parámetros. Regresión lineal, regresión logística, Naive Bayes. Rápidos, interpretables, pero asumen una forma funcional.
  • No paramétricos: el número de parámetros crece con los datos. KNN, árboles, SVM con kernel, procesos gaussianos. Más flexibles, pero pueden ser costosos y sobreajustar.

Hiperparámetros que más importan

ModeloHiperparámetros claveEfecto
Regresión Ridge/Lasso$\alpha$Más $\alpha$ → más regularización, menos overfitting
KNN$k$, distancia, pesos$k$ pequeño → frontera compleja; $k$ grande → suaviza
Árbol de decisiónProfundidad, mín. muestras por hojaMás profundidad → más capacidad
Random ForestNº árboles, max_features, profundidadMás árboles → más estabilidad (con costo)
SVM$C$, kernel, $\gamma$$C$ y $\gamma$ altos → frontera compleja
Gradient BoostingNº árboles, lr, profundidad, subsampleCombinación delicada; lr bajo + más árboles suele funcionar
Red neuronalCapas, neuronas, lr, dropout, batch sizeArquitectura y regularización
No existe «el mejor hiperparámetro» universal Depende del dataset, del tamaño, del ruido y de la métrica. Por eso se buscan empíricamente con validación. Copiar hiperparámetros de un tutorial sin validarlos es una receta para el fracaso.

Un ejemplo concreto: KNN

Con $k=1$, cada punto de entrenamiento es su propio vecino: la frontera pasa por todos los puntos y el error de entrenamiento es cero, pero el de test suele ser alto. Con $k=n$, todos predicen la clase mayoritaria: underfitting extremo. El valor óptimo está en medio y se encuentra con validación cruzada.

Pythonhiperparametros.py
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import cross_val_score
import numpy as np

for k in [1, 3, 5, 11, 21, 51]:
    modelo = KNeighborsClassifier(n_neighbors=k)
    scores = cross_val_score(modelo, X, y, cv=5, scoring="accuracy")
    print(f"k={k:2d}  accuracy={scores.mean():.3f} ± {scores.std():.3f}")

La curva típica de accuracy vs. $k$ tiene forma de U invertida. Ese es el compromiso sesgo–varianza en acción.

Ejercicio 3.4
  1. Clasifica: (a) coeficientes de una regresión; (b) número de vecinos en KNN; (c) pesos de una red; (d) profundidad máxima de un árbol; (e) media aprendida por un escalador. Parámetros: a, c, e. Hiperparámetros: b, d.
  2. ¿Qué esperas si usas un polinomio de grado 50 con 20 puntos? Overfitting: pasa por todos los puntos y oscila entre ellos.
  3. ¿Qué harías si el error de train es 0.01 y el de validación 0.40? Reducir capacidad o regularizar; recoger más datos; simplificar features.
Lección 3.5

Funciones de pérdida y optimización

20 minMatemática aplicadaMSE + cross-entropy

La función de pérdida define qué significa equivocarse. Elegirla mal puede hacer que un modelo optimice lo que no importa. No es un detalle técnico: es una decisión de diseño.

Pérdidas para regresión

MSE, MAE y Huber $$\text{MSE}=\frac1n\sum_{i=1}^{n}(y_i-\hat{y}_i)^2, \qquad \text{MAE}=\frac1n\sum_{i=1}^{n}|y_i-\hat{y}_i|$$ $$\text{Huber}_\delta(e)=\begin{cases}\frac12e^2 & |e|\leq\delta\\ \delta(|e|-\frac12\delta) & |e|>\delta\end{cases}$$ MSE penaliza fuerte los errores grandes; MAE es robusta a outliers; Huber combina ambas.
PérdidaSensible a outliersDerivadaCuándo usar
MSEAltaSuaveRuido gaussiano, sin outliers extremos
MAEBajaNo derivable en 0Outliers, métrica de negocio absoluta
HuberMediaSuaveCompromiso práctico

Pérdidas para clasificación

Entropía cruzada binaria $$L(y,p)=-\left[y\log p+(1-y)\log(1-p)\right]$$ $y\in\{0,1\}$; $p=P(y=1\mid x)$. Si $y=1$ y $p\to0$, la pérdida $\to\infty$: castiga con dureza la confianza equivocada.
Entropía cruzada multiclase $$L(\mathbf{y},\mathbf{p})=-\sum_{k=1}^{K}y_k\log p_k, \qquad p_k=\frac{e^{z_k}}{\sum_j e^{z_j}}\;(\text{softmax})$$

La entropía cruzada es la pérdida estándar en clasificación porque proviene de maximizar la verosimilitud de la clase correcta. Para $K$ clases, el modelo produce un vector de probabilidades que suma 1.

1 Comparar dos predicciones

Etiqueta real $y=1$. Modelo A predice $p=0.9$; modelo B predice $p=0.6$.

A
$L_A=-\log(0.9)=0.105$.
B
$L_B=-\log(0.6)=0.511$.

El modelo A es mucho mejor según la log-loss, aunque ambos aciertan la clase. La pérdida premia la confianza calibrada, no solo el acierto.

Otras pérdidas

  • Hinge: $\max(0,1-y\,f(x))$, usada en SVM; margen y clasificación correcta.
  • Focal loss: modula la entropía cruzada para enfocarse en ejemplos difíciles; común en detección de objetos.
  • Triplet / contrastiva: acerca representaciones de ejemplos similares y aleja las distintas; base de embeddings.
  • Dice / IoU: segmentación de imágenes, donde el desbalance píxel a píxel es extremo.

Optimización: qué significa resolver

Minimizar una pérdida es un problema de optimización. Si la función es convexa, cualquier mínimo local es global. Si no, el resultado depende de la inicialización y del optimizador. En la práctica no buscamos el mínimo global exacto: buscamos un modelo que generalice bien.

Descenso del gradiente estocástico $$\theta_{t+1}=\theta_t-\eta\,\nabla_\theta L\left(\theta_t;\, \mathcal{B}_t\right)$$ $\mathcal{B}_t$ es un mini-batch. El gradiente es una estimación ruidosa del gradiente completo.
Pythonperdidas.py
import numpy as np

def mse(y, yp):
    return np.mean((y - yp) ** 2)

def mae(y, yp):
    return np.mean(np.abs(y - yp))

def huber(y, yp, delta=1.0):
    e = y - yp
    return np.mean(np.where(np.abs(e) <= delta,
                            0.5 * e**2,
                            delta * (np.abs(e) - 0.5 * delta)))

def bce(y, p, eps=1e-12):
    p = np.clip(p, eps, 1 - eps)
    return -np.mean(y * np.log(p) + (1 - y) * np.log(1 - p))

y = np.array([1, 0, 1, 1])
p = np.array([0.9, 0.2, 0.8, 0.6])
print("BCE:", bce(y, p))       # 0.288

y_real = np.array([3., -0.5, 2., 7.])
y_pred = np.array([2.5, 0.0, 2., 8.])
print("MSE:", mse(y_real, y_pred))
print("MAE:", mae(y_real, y_pred))
print("Huber:", huber(y_real, y_pred))
La pérdida y la métrica no son lo mismo Puedes entrenar con entropía cruzada y evaluar con F1, o entrenar con MSE y evaluar con MAE. La pérdida debe ser optimizable; la métrica debe reflejar el objetivo real. Cuando divergen mucho, considera una pérdida alineada con el negocio o ajusta el umbral.
Ejercicios 3.5
  1. Calcula la BCE para $y=0$, $p=0.1$: $-\log(0.9)=0.105$.
  2. Para $y=(1,1,0)$, $p=(0.8,0.6,0.3)$: BCE $=-\frac13(\ln0.8+\ln0.6+\ln0.7)\approx0.363$.
  3. ¿Por qué MAE no es ideal con descenso del gradiente? Su derivada es constante salvo en 0; cerca del mínimo oscila y no converge suavemente.
  4. Un modelo predice probabilidades de 0.99 para todas las transacciones y todas son normales. ¿Qué métrica lo delata? Log-loss y calibración, no accuracy (sería 99%+).
Lección 3.6

Generalización, bias-variance y regularización

24 minEl concepto centralSimulador incluido

Un modelo generaliza si funciona bien en datos nuevos. El overfitting es memorizar el ruido del entrenamiento; el underfitting es no capturar ni la señal. Entre ambos hay un equilibrio que se gestiona con capacidad y regularización.

Descomposición sesgo–varianza

Para pérdida cuadrática $$\mathbb{E}\left[(y-\hat{f}(x))^2\right] = \underbrace{\sigma^2}_{\text{ruido}} + \underbrace{\left(\mathbb{E}[\hat{f}(x)]-f(x)\right)^2}_{\text{sesgo}^2} + \underbrace{\mathbb{E}\left[\left(\hat{f}(x)-\mathbb{E}[\hat{f}(x)]\right)^2\right]}_{\text{varianza}}$$ El ruido es irreducible. El sesgo mide cuán lejos está el modelo promedio de la verdad; la varianza, cuánto cambia entre muestras.
SituaciónSesgoVarianzaSíntomaRemedio
UnderfittingAltoBajaError alto en train y validaciónMás capacidad, mejores features
EquilibrioMedioMediaGap pequeño y error bajo—
OverfittingBajaAltaTrain bajo, validación altaRegularizar, más datos, simplificar
Intuición Un modelo de bias alto es como un arco mal calibrado: siempre falla hacia el mismo lado. Uno de varianza alta es como un tirador nervioso: acierta a veces, pero sus flechas se dispersan. Queremos un tirador centrado y consistente.

Curvas de aprendizaje

Graficar el error de entrenamiento y validación en función de:

  • El tamaño del entrenamiento: si ambas curvas convergen a un error alto, hay underfitting. Si hay una brecha grande, overfitting o necesidad de más datos.
  • La complejidad del modelo: a mayor complejidad, el error de train baja siempre; el de validación baja y luego sube. El mínimo de validación es el punto óptimo.
  • Las épocas: en redes, la validación empeora tras cierto punto; el early stopping corta ahí.
∿

Simulador · Overfitting y underfitting

Ajusta un polinomio de grado variable a datos ruidosos y observa el error de train vs. test.

MSE train = —
MSE test = —
Diagnóstico: —
Verde: train. Naranja: test. Azul: ajuste. Los puntos grises son datos de test no vistos.

Regularización

Regularizar es añadir una penalización a la pérdida para limitar la complejidad de los parámetros:

Ridge (L2), Lasso (L1) y Elastic Net $$L_{\text{ridge}}=L+\lambda\|\mathbf{w}\|_2^2, \qquad L_{\text{lasso}}=L+\lambda\|\mathbf{w}\|_1, \qquad L_{\text{EN}}=L+\lambda\left(\alpha\|\mathbf{w}\|_1+(1-\alpha)\|\mathbf{w}\|_2^2\right)$$ $\lambda$ controla la fuerza. L2 encoge los pesos; L1 además los lleva a cero y selecciona features.
TécnicaCómo reduce overfittingCoste
Regularización L1/L2Limita la magnitud de los pesosSesgo introducido; requiere escalar features
Más datosReduce la varianza de la estimaciónCostoso o imposible
Simplificar el modeloMenos capacidadPuede aumentar el sesgo
Early stoppingDetiene antes de memorizarNecesita validación
DropoutDesactiva neuronas al azarEntrenamiento más lento
Data augmentationAmplía la variedad de ejemplosTransformaciones válidas para el dominio
EnsemblesPromediar modelos reduce varianzaMás cómputo e interpretación difícil
Pythonregularizacion.py
from sklearn.linear_model import Ridge, Lasso, ElasticNet
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import make_pipeline
from sklearn.model_selection import cross_val_score

# Importante: escalar antes de regularizar
for alpha in [0.001, 0.01, 0.1, 1, 10, 100]:
    ridge = make_pipeline(StandardScaler(), Ridge(alpha=alpha))
    lasso = make_pipeline(StandardScaler(), Lasso(alpha=alpha, max_iter=10_000))
    r = cross_val_score(ridge, X, y, cv=5, scoring="r2").mean()
    l = cross_val_score(lasso, X, y, cv=5, scoring="r2").mean()
    print(f"alpha={alpha:>6}  ridge={r:.3f}  lasso={l:.3f}")

# Inspeccionar coeficientes de Lasso
lasso = make_pipeline(StandardScaler(), Lasso(alpha=0.1)).fit(X, y)
coefs = lasso[-1].coef_
print("features con peso cero:", (coefs == 0).sum(), "de", len(coefs))
Diagnóstico rápido Si el error de train es bajo y el de validación alto: reduce capacidad o regulariza. Si ambos son altos: aumenta capacidad o mejora las features. Si la brecha es pequeña pero el error es alto: el problema está en los datos o en la formulación, no en el modelo.
Ejercicios 3.6
  1. Un modelo tiene MSE train 0.05 y validación 0.35. ¿Overfitting o underfitting? Overfitting; prueba regularización o más datos.
  2. ¿Qué esperas si aumentas $\lambda$ en Ridge hasta infinito? Los pesos tienden a cero; el modelo predice la media y aumenta el sesgo.
  3. ¿Por qué Lasso puede seleccionar features? Porque la geometría de la norma L1 tiene vértices en los ejes; el óptimo suele caer en uno de ellos, con coeficientes exactamente cero.
  4. Explica por qué añadir ruido a los datos de entrenamiento puede reducir la varianza. Actúa como regularización: impide que el modelo se ajuste a particularidades exactas.
Lección 3.7

El pipeline de Machine Learning

20 minIngenieríaScikit-learn

Un pipeline encadena transformaciones y un modelo final en un solo objeto. Garantiza que el preprocesamiento se ajuste solo con train, evita fugas y hace que el despliegue sea reproducible.

Flujo completo

  1. Definir el problema y la métrica.
  2. Cargar y auditar los datos.
  3. Dividir train / validación / test.
  4. Explorar solo el train (estadísticas, gráficos).
  5. Construir el pipeline de preprocesamiento + modelo.
  6. Validar con cross-validation y buscar hiperparámetros.
  7. Entrenar el modelo final con train+validación.
  8. Evaluar una vez en test.
  9. Analizar errores e interpretar.
  10. Serializar, desplegar y monitorear.

Pipeline con columnas numéricas y categóricas

Pythonpipeline.py
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.impute import SimpleImputer
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import classification_report, roc_auc_score

# Dataset de ejemplo (reemplaza por el tuyo)
from sklearn.datasets import fetch_openml
# titanic = fetch_openml("titanic", version=1, as_frame=True).frame

# Simulamos un DataFrame con columnas mixtas
rng = np.random.default_rng(42)
n = 400
df = pd.DataFrame({
    "edad": rng.normal(38, 12, n).round(),
    "tarifa": rng.lognormal(3, 1, n).round(2),
    "clase": rng.choice(["primera", "segunda", "tercera"], n),
    "puerto": rng.choice(["S", "C", "Q"], n),
    "sobrevivio": rng.integers(0, 2, n),
})
df.loc[rng.choice(n, 30), "edad"] = np.nan

X = df.drop(columns="sobrevivio")
y = df["sobrevivio"]

num_cols = ["edad", "tarifa"]
cat_cols = ["clase", "puerto"]

preprocesador = ColumnTransformer([
    ("num", Pipeline([
        ("imputar", SimpleImputer(strategy="median")),
        ("escalar", StandardScaler()),
    ]), num_cols),
    ("cat", Pipeline([
        ("imputar", SimpleImputer(strategy="most_frequent")),
        ("onehot", OneHotEncoder(handle_unknown="ignore")),
    ]), cat_cols),
])

pipeline = Pipeline([
    ("prep", preprocesador),
    ("modelo", RandomForestClassifier(random_state=42)),
])

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

parametros = {
    "modelo__n_estimators": [100, 300],
    "modelo__max_depth": [None, 5, 10],
    "modelo__min_samples_leaf": [1, 3, 5],
}

busqueda = GridSearchCV(pipeline, parametros, cv=5, scoring="roc_auc", n_jobs=-1)
busqueda.fit(X_train, y_train)

print("mejores params:", busqueda.best_params_)
print("mejor CV AUC:", round(busqueda.best_score_, 3))

y_pred = busqueda.predict(X_test)
y_prob = busqueda.predict_proba(X_test)[:, 1]
print(classification_report(y_test, y_pred))
print("AUC test:", round(roc_auc_score(y_test, y_prob), 3))
El pipeline se ajusta completo GridSearchCV reajusta el preprocesamiento dentro de cada fold. Por eso es seguro: las estadísticas de imputación y escalado se calculan solo con el train del fold. Si preprocesas fuera y pasas los datos transformados, vuelve la fuga.

Errores frecuentes en el pipeline

  • Escalar o imputar antes de dividir.
  • Incluir el ID como feature.
  • Usar la etiqueta para construir una feature.
  • Evaluar en test más de una vez y ajustar decisiones con esa información.
  • No versionar el pipeline: el modelo serializado debe incluir el preprocesamiento.
  • Entrenar con una distribución y desplegar en otra sin monitoreo.

Línea base: el modelo que debes superar

Siempre empieza con una baseline. En clasificación, predecir la clase mayoritaria; en regresión, predecir la media. Si tu modelo complejo no supera claramente la baseline, no justifica su costo. Documenta la mejora con intervalos de confianza.

Cierre del módulo Ya tienes el marco: datos representativos, split honesto, pérdida alineada, modelo con capacidad adecuada, regularización y evaluación en datos no vistos. Todos los algoritmos del Módulo 4 encajan en este marco; ninguno lo sustituye.
Ejercicios 3.7
  1. Construye un pipeline para el dataset Titanic con imputación, one-hot y regresión logística. Reporta AUC con validación cruzada.
  2. Compara el pipeline con una baseline que predice siempre la clase mayoritaria. ¿Cuánto mejora?
  3. Elimina una feature sospechosa de fuga y observa el cambio en la métrica. Documenta el resultado.
  4. Serializa el pipeline completo con joblib y vuelve a cargarlo; comprueba que predice lo mismo.
Curso de Machine Learning · teoría, matemáticas y práctica en Python Progreso local · 0% completado · Hecho para estudiar en cualquier lugar