Python & Data Science

Validación cruzada anidada: cómo ajustar tu modelo sin engañarte a ti mismo

1. El modelo ‘ganador’ que en realidad perdió

Todos hemos estado ahí. Pasas horas ajustando hiperparámetros. Ejecutas un GridSearchCV, y los resultados se ven geniales. La validación cruzada alcanza 95%, y sientes que eres un mago del aprendizaje automático. Despliegas el modelo a producción—y luego el rendimiento cae a 80% con datos del mundo real.

¿Qué pasó? No solo entrenaste un modelo. ‘Hiciste trampa’ sin darte cuenta. Esto es sesgo optimista.

La validación cruzada estándar filtra información porque la selección del modelo es en sí misma parte del entrenamiento. Piensa en un estudiante que llega a ver las preguntas del examen mientras estudia. Incluso sin memorizar las respuestas exactas, sabe en qué temas debe centrarse. Elige los ‘mejores’ parámetros basándote en un conjunto de prueba, y ese conjunto ya no es verdaderamente no visto. Ya ha influenciado tus decisiones.

Así es como se ve esto en código. Crearemos un conjunto de datos con mucho ruido y muy pocas muestras—una receta para el sobreajuste.

import numpy as np
from sklearn.datasets import make_classification
from sklearn.model_selection import GridSearchCV, KFold
from sklearn.svm import SVC

# Create a noisy dataset where most features are just random noise
X, y = make_classification(n_samples=100, n_features=100, n_informative=2, 
                           n_redundant=98, random_state=42)

# Define a search space for an SVM
param_grid = {'C': [0.1, 1, 10, 100], 'gamma': [1, 0.1, 0.01, 0.001]}
inner_cv = KFold(n_splits=5, shuffle=True, random_state=42)

# Standard GridSearchCV
clf = GridSearchCV(estimator=SVC(), param_grid=param_grid, cv=inner_cv)
clf.fit(X, y)

print(f"Best Score from Standard CV: {clf.best_score_:.4f}")

En este ejemplo, best_score_ podría devolver 0.92. Pero como usamos los mismos datos tanto para encontrar los mejores C y gamma como para reportar la puntuación, ese 0.92 es una mentira. El modelo ‘sabe’ qué parámetros funcionaron mejor para esta porción específica de datos.

2. La intuición: dos tareas, dos barreras

La solución es reconocer que tenemos dos trabajos distintos, y que necesitan datos diferentes.

Trabajo 1: Ajuste (El Bucle Interno). Encontrar las mejores perillas para girar. Dados estos datos de entrenamiento específicos, ¿qué hiperparámetros funcionan mejor?

Trabajo 2: Evaluación (El Bucle Externo). Comprobar si todo nuestro proceso realmente funciona. Si uso mi método de ajuste con datos nuevos, ¿qué tan bien funcionará?

Imagina a un entrenador realizando audiciones para elegir al mejor jugador: ese es el Bucle Interno. Pero ser elegido no gana un campeonato. El equipo aún tiene que jugar un partido real contra un oponente que nunca han visto. Ese es el Bucle Externo. La audición es el ajuste; el partido es la evaluación.

3. Visualizando los bucles: una caja dentro de otra

La validación cruzada anidada es un bucle dentro de un bucle. Esta es la parte más difícil de entender, así que aquí está la lógica.

  1. El bucle externo divide los datos en un conjunto ‘reservado’ (Test) y un conjunto de ‘trabajo’ (Train).
  2. El bucle interno toma ese conjunto de ‘trabajo’ y lo divide nuevamente en múltiples partes más pequeñas para encontrar los mejores hiperparámetros.
  3. Los ‘mejores’ parámetros encontrados en el bucle interno se prueban luego en el conjunto ‘reservado’ del bucle externo.

Aquí está en pseudocódigo:

# Pseudo-code for the logic
# for train_idx, test_idx in outer_cv.split(X):
#     X_train, X_test = X[train_idx], X[test_idx]
#     
#     # INNER LOOP: Find best params using ONLY X_train
#     # for inner_train, inner_val in inner_cv.split(X_train):
#     #     ... find best settings ...
#     
#     # EVALUATION: Test those best settings on X_test
#     # score = model.score(X_test)

Los ‘mejores’ parámetros pueden variar en cada partición externa. No estamos probando un modelo específico; estamos probando nuestro procedimiento para encontrar uno.

4. Veamos qué pasa: programando el bucle doble

Scikit-Learn nos evita tener que escribir estos bucles anidados a mano. Puedes envolver un objeto GridSearchCV dentro de una función cross_val_score.

from sklearn.model_selection import cross_val_score

# The Outer Loop: 5-fold CV
outer_cv = KFold(n_splits=5, shuffle=True, random_state=42)

# The Inner Loop: GridSearchCV (which handles its own internal CV)
inner_clf = GridSearchCV(estimator=SVC(), param_grid=param_grid, cv=inner_cv)

# Run the Nested CV
nested_scores = cross_val_score(inner_clf, X, y, cv=outer_cv)

print(f"Nested CV Scores: {nested_scores}")
print(f"Average Nested CV Score: {nested_scores.mean():.4f}")

Así que, observa los números. Si tu puntaje de CV estándar era 0.92 pero tu puntaje de CV anidado es 0.78, confía en el 0.78. Esa diferencia de 0.14 significa que sobreajustaste el proceso de ajuste. El puntaje más bajo no es un fracaso. Solo significa que tu receta para construir el modelo es menos confiable de lo que pensabas.

5. Pero espera—¿qué modelo pongo en producción?

Esta es la confusión más común: “Si la CV anidada me da 5 puntuaciones diferentes y potencialmente 5 conjuntos diferentes de ‘mejores’ parámetros, ¿qué modelo va a producción?”

Ninguno de ellos.

La CV anidada estima el error. No selecciona tu modelo final. Lo que te indica es qué tan bien funciona realmente tu receta — digamos, SVM más Grid Search. Una vez que hayas confirmado que la receta es buena, reentrenas con el conjunto completo de datos utilizando la lógica del bucle interno.

# Final Step: Retrain on all data to get the production model
final_model = GridSearchCV(estimator=SVC(), param_grid=param_grid, cv=inner_cv)
final_model.fit(X, y)

# This 'final_model' is what you save and deploy
print(f"Final Parameters: {final_model.best_params_}")

Este es el momento ‘¡Ajá!’. La CV anidada valida la receta, no solo el pastel. Cuando envías el modelo final a producción, ya tienes una expectativa realista de cómo se desempeñará, porque probaste el proceso, no solo el resultado.

Resumen:

  • La CV estándar puede ser demasiado optimista porque se filtra información del ajuste.
  • La CV anidada usa un Bucle Externo para la evaluación y un Bucle Interno para el ajuste.
  • El resultado es una estimación realista del error, no un modelo final.
  • Reentrena con tu conjunto completo de datos una vez que la validación anidada te dé confianza en tu enfoque.

Comprueba tu comprensión

Las preguntas a continuación avanzan desde el simple recuerdo hasta el diseño abierto, siguiendo aproximadamente la Taxonomía de Bloom.

Recordar ¿Cuáles son los dos “trabajos” separados que el artículo le asigna al bucle interno y al bucle externo?

Comprender Con tus propias palabras, explica por qué el best_score_ del GridSearchCV estándar es “una mentira”, utilizando la analogía del artículo sobre el “estudiante que ve las preguntas del examen mientras estudia”.

Aplicar Usando los números de ejemplo del artículo (puntuación CV estándar de 0.92, puntuación de CV anidada de 0.78), ¿qué te dice la brecha de 0.14 sobre la confiabilidad de la puntuación de validación cruzada estándar y qué número deberías reportar realmente a una parte interesada?

Analizar El artículo dice que la CV anidada “podría ser diferente en cada pliegue externo” para los mejores parámetros, y que esto está bien porque “no estamos probando un modelo específico; estamos probando nuestro procedimiento”. Explica paso a paso por qué sería un error simplemente elegir el pliegue externo que produjo la mejor puntuación individual y enviar a producción los hiperparámetros específicos de ese pliegue.

Evaluar El paso final del artículo vuelve a entrenar con el conjunto completo de datos utilizando la lógica del bucle interno (GridSearchCV nuevamente) para producir el modelo de producción. Critica este paso: dado que la CV anidada en realidad nunca evalúa este modelo final específico (evalúa el procedimiento a través de diferentes pliegues), ¿qué suposición estás asumiendo implícitamente para confiar en que el rendimiento del modelo final en el mundo real coincidirá con la estimación de la CV anidada?

Crear Diseña un plan de validación cruzada anidada para un nuevo escenario: un equipo tiene solo 150 ejemplos etiquetados (muy pequeño) y desea ajustar el max_depth y n_estimators de un Random Forest. Dado el pequeño tamaño de la muestra, propone cuántos pliegues externos e internos usarías, y explica el equilibrio entre más pliegues (estimación más confiable) y menos pliegues (más datos de entrenamiento por pliegue) en este contexto específico de pocos datos.


Aplica lo que aprendiste

Entregable: Un memo de 200–400 palabras para los stakeholders de tu proyecto. Escenario: Ejecutaste GridSearchCV (SVC con una grilla de C/gamma, KFold interno de 5 pliegues) en el dataset ruidoso del artículo—100 muestras, 100 características, 98 de ellas puro ruido—y best_score_ devolvió 0.92. Luego envolviste ese mismo GridSearchCV dentro de cross_val_score con un KFold externo de 5 pliegues y el puntaje anidado cayó a 0.78. Los stakeholders preguntan: “¿Por qué cayó la exactitud? ¿Podemos simplemente reportar el 0.92?” Escribe un memo que defienda el 0.78, explique la brecha de 0.14, e indique qué enviarás finalmente a producción.

Rúbrica (lista de verificación):

  • Identifica la causa raíz: el GridSearchCV estándar usa los mismos datos tanto para seleccionar el mejor C/gamma como para evaluarlos, por lo que best_score_ está sesgado de forma optimista por fuga de información.
  • Explica la brecha de 0.14 como el tamaño del sobreajuste introducido por el proceso de ajuste mismo—no es un bug, no es un modelo peor, sino el costo de evaluar de forma honesta.
  • Indica que la CV anidada evalúa el procedimiento (SVM + Grid Search), no un único modelo entrenado; por lo tanto, los hiperparámetros “óptimos” pueden diferir entre los pliegues externos y eso es esperado y aceptable.
  • Especifica el paso a producción: reentrenar un GridSearchCV nuevo en el dataset completo usando la misma lógica del bucle interno, enviar ese modelo a producción y reportar 0.78 como la exactitud esperada en el mundo real.
  • Usa un lenguaje accesible para stakeholders—incluye al menos una analogía en lenguaje sencillo sobre por qué reutilizar datos para el ajuste y la evaluación infla el número (por ejemplo, el “estudiante que ve las preguntas del examen mientras estudia” del artículo).

Esta traducción fue generada automáticamente y puede contener errores. Si el idioma inglés es tu preferencia, puedes leer el artículo original en inglés .

¿Buscas otra cosa?

Busca en todos los artículos por título, resumen o tema.