14. Validación cruzada paso a paso

14.1 El problema de depender de una sola partición

Cuando dividimos los datos en entrenamiento y prueba, el resultado puede cambiar bastante según qué casos hayan quedado en cada grupo. Con datasets pequeños o medianos, esa variación puede ser importante.

Eso significa que un modelo podría parecer muy bueno con una partición y más regular con otra. Entonces surge una pregunta razonable: ¿cómo obtener una evaluación más estable?

La respuesta más usada es la validación cruzada.

14.2 Qué es la validación cruzada

La validación cruzada consiste en dividir el dataset en varias partes llamadas folds. En cada vuelta:

  • una parte se usa para validar;
  • las demás se usan para entrenar.

Luego el proceso se repite cambiando qué fold queda reservado para validación. Al final se obtienen varias métricas y se analiza el promedio.

14.3 La idea intuitiva

Si usamos validación cruzada con 5 folds:

  • el dataset se divide en 5 bloques;
  • el modelo se entrena 5 veces;
  • cada bloque actúa una vez como validación;
  • las otras 4 veces actúa como parte del entrenamiento.

Así, todos los datos participan tanto en entrenamiento como en validación, pero nunca cumplen ambas funciones al mismo tiempo en la misma iteración.

14.4 Por qué este método es útil

La validación cruzada ayuda a:

  • obtener una estimación más robusta del rendimiento del modelo;
  • reducir la dependencia de una única partición;
  • comparar modelos o hiperparámetros con mayor confianza;
  • aprovechar mejor datasets no muy grandes.

No reemplaza por completo al conjunto de prueba final cuando queremos una evaluación definitiva, pero sí es una herramienta excelente para seleccionar enfoques durante el desarrollo.

14.5 Ejemplo muy claro: aprobar o no aprobar

Vamos a usar un problema sencillo de clasificación: predecir si un estudiante aprobará según sus horas de estudio y la cantidad de prácticas realizadas.

Aplicaremos un modelo KNN y lo evaluaremos con validación cruzada de 4 folds. Veremos la exactitud obtenida en cada vuelta y el promedio final.

import pandas as pd
from sklearn.model_selection import StratifiedKFold, cross_val_score
from sklearn.neighbors import KNeighborsClassifier

datos = pd.DataFrame({
    "horas_estudio": [1, 2, 2, 3, 4, 5, 6, 6, 7, 8, 9, 10],
    "practicas": [0, 1, 1, 1, 2, 3, 3, 4, 4, 5, 5, 6],
    "aprobo": [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1]
})

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

modelo = KNeighborsClassifier(n_neighbors=3)

cv = StratifiedKFold(n_splits=4, shuffle=True, random_state=42)
scores = cross_val_score(modelo, X, y, cv=cv, scoring="accuracy")

print("Exactitud en cada fold:", scores)
print("Promedio de exactitud:", scores.mean())
print("Desviación estándar:", scores.std())

modelo.fit(X, y)

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

prediccion = modelo.predict(nuevo_estudiante)[0]
print("Predicción para el nuevo estudiante:", prediccion)

Salida resumida esperada:

Exactitud en cada fold: [...]
Promedio de exactitud: ...
Desviación estándar: ...
Predicción para el nuevo estudiante: ...

14.6 Qué está pasando en el ejemplo

En lugar de hacer una única división entre entrenamiento y prueba, cross_val_score repite el entrenamiento y la evaluación varias veces.

Como usamos StratifiedKFold, cada fold intenta conservar una proporción parecida entre aprobados y no aprobados. Eso es importante en clasificación, porque evita particiones muy desbalanceadas.

14.7 Explicación detallada del código

  • StratifiedKFold(n_splits=4, shuffle=True, random_state=42): define una validación cruzada de 4 folds, mezclando los datos y manteniendo el equilibrio entre clases.
  • cross_val_score(...): entrena y evalúa el modelo una vez por cada fold.
  • scores: guarda la exactitud obtenida en cada iteración.
  • scores.mean(): calcula el rendimiento promedio.
  • scores.std(): muestra cuánta variación hubo entre folds.

Ese último punto es muy útil: no solo interesa el promedio, también interesa si los resultados son estables o cambian demasiado.

14.8 Cómo interpretar el promedio y la desviación

Si el promedio de exactitud es alto y la desviación estándar es baja, el modelo parece rendir bien de forma consistente.

Si el promedio es aceptable, pero la desviación es muy grande, hay una señal de inestabilidad: el modelo funciona bien con algunos folds y peor con otros.

En ese caso conviene revisar:

  • si el dataset es pequeño;
  • si las clases están desbalanceadas;
  • si el modelo es demasiado sensible;
  • si faltan pasos de preparación de datos.

14.9 Cuándo usar validación cruzada

La validación cruzada es especialmente recomendable cuando:

  • quieres comparar varios modelos;
  • quieres elegir hiperparámetros;
  • tienes pocos datos y no quieres depender de una sola división;
  • quieres una evaluación más confiable durante el desarrollo.

Es habitual combinarla más adelante con herramientas como GridSearchCV, que veremos en otro tema.

14.10 Errores frecuentes

  • Creer que el promedio cuenta toda la historia: también conviene mirar la variación entre folds.
  • Olvidar la estratificación en clasificación: puede generar particiones poco representativas.
  • Usar validación cruzada y luego volver a ajustar decisiones sobre prueba demasiadas veces: eso también contamina la evaluación final.
  • Interpretar la validación cruzada como magia: mejora la evaluación, pero no arregla datos pobres ni variables mal elegidas.

14.11 Qué deberías retener

  • La validación cruzada repite entrenamiento y validación sobre distintas particiones.
  • Ayuda a reducir la dependencia de una sola división del dataset.
  • cross_val_score permite aplicarla de forma simple en Scikit-learn.
  • El promedio de los folds resume el rendimiento; la desviación muestra la estabilidad.
  • Es una herramienta clave para comparar modelos y ajustar decisiones con más criterio.