ScikitLearn: Validación de modelos
La validación de modelos es un paso esencial en el proceso de aprendizaje automático, pues permite estimar la capacidad de generalización que alcanzará el sistema al enfrentarse a datos nuevos. En scikit learn, la validación se apoya en diversos métodos y funciones del submódulo sklearn.model_selection
, que incluye desde la simple división train/test hasta la validación cruzada. El fin principal de estas técnicas es aportar una visión honesta del rendimiento que ofrecerá el modelo, evitando que se establezcan conclusiones excesivamente optimistas.
El esquema más básico es la separación en dos subconjuntos: entrenamiento (train) y prueba (test). Con train_test_split
, se deja un porcentaje de datos para entrenar el modelo y otro para evaluarlo. Por ejemplo, reservar el 80% para entrenamiento y el 20% para prueba:
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
model = LogisticRegression()
model.fit(X_train, y_train)
score = model.score(X_test, y_test)
print("Exactitud en test:", score)
Este método resulta sencillo, pero depende de la aleatoriedad de una única partición. Cambiar la semilla (random_state
) o el tamaño de la partición puede conducir a variaciones en la estimación de rendimiento.
Para ganar mayor fiabilidad, se recurre a la validación cruzada (cross-validation), donde se dividen los datos en k partes (folds) y se realiza una rotación en la que cada fold funciona de forma alternada como subconjunto de prueba. Una vez completadas las k iteraciones, se calcula la media de las métricas obtenidas. Con sklearn.model_selection.cross_val_score
, se agiliza la aplicación de este procedimiento.
from sklearn.model_selection import cross_val_score, KFold
from sklearn.svm import SVC
cv = KFold(n_splits=5, shuffle=True, random_state=42)
svc = SVC(kernel='linear', C=1.0)
scores = cross_val_score(svc, X, y, cv=cv, scoring='accuracy')
print("Exactitud media:", scores.mean())
La validación cruzada reduce la varianza de la estimación, ya que cada muestra es empleada tanto para entrenamiento como para prueba en diferentes iteraciones. Además, es posible equilibrar la distribución de clases con StratifiedKFold
, muy útil cuando se trabaja con problemas de clasificación desbalanceados.
En situaciones donde se desea optimizar o buscar hiperparámetros (por ejemplo, C
en SVM o la profundidad de un árbol), scikit learn dispone de GridSearchCV
y RandomizedSearchCV
. Estos métodos combinan la búsqueda de parámetros y la validación cruzada, ajustando distintas configuraciones y evaluándolas de manera sistemática para encontrar la que ofrece un mayor rendimiento.
from sklearn.model_selection import GridSearchCV
param_grid = {'C': [0.1, 1, 10], 'kernel': ['linear', 'rbf']}
grid_search = GridSearchCV(svc, param_grid=param_grid, cv=5, scoring='accuracy')
grid_search.fit(X, y)
print("Mejor combinación:", grid_search.best_params_)
print("Mejor puntuación:", grid_search.best_score_)
Cuando se aplican estos enfoques, es importante evitar la fuga de información, sobre todo si antes se hace un preprocesamiento o selección de características. Para ello, se recomienda estructurar el flujo completo en un Pipeline
, de modo que las transformaciones se ajusten solo con los datos de entrenamiento en cada fold, sin contaminar los datos de prueba.
Existen también variantes específicas como Leave-One-Out Cross-Validation (LOOCV), donde cada instancia se emplea como conjunto de prueba, y el resto conforman el conjunto de entrenamiento. Esto ofrece un uso muy intensivo de los datos, pero conlleva un coste computacional alto y tiende a presentar mayor varianza en la estimación.
En problemas de series temporales, no basta con barajar aleatoriamente, ya que la información cronológica no puede mezclarse libremente. Con TimeSeriesSplit
, cada partición se organiza de manera que el conjunto de entrenamiento siempre preceda temporalmente al de prueba. Este procedimiento evita mirar hacia el futuro durante el entrenamiento y refleja más fielmente el rendimiento que se obtendría en el mundo real.
from sklearn.model_selection import TimeSeriesSplit
tss = TimeSeriesSplit(n_splits=5)
for train_index, test_index in tss.split(X):
X_train, X_test = X[train_index], X[test_index]
y_train, y_test = y[train_index], y[test_index]
model.fit(X_train, y_train)
score = model.score(X_test, y_test)
print("Score temporal:", score)
Además de los esquemas de partición, la selección de la métrica adecuada es determinante para evaluar el comportamiento de un modelo. Clásicamente se emplean accuracy_score
o mean_squared_error
, pero en contextos con clases muy desequilibradas conviene monitorizar la sensibilidad (recall) o la puntuación F1, mientras que en tareas de regresión con escalas desiguales se recurre a métricas relativas como el MAPE (error porcentual absoluto medio).
En experimentos extensos, puede ser útil la validación cruzada anidada (nested cross-validation). La capa externa de validación cruzada calcula el rendimiento, y en cada pliegue se ejecuta internamente un proceso de búsqueda de hiperparámetros con GridSearchCV
o RandomizedSearchCV
. Este esquema reduce el sesgo en la estimación de la puntuación final, si bien eleva considerablemente el coste computacional.
from sklearn.model_selection import cross_val_score, KFold
outer_cv = KFold(n_splits=5, shuffle=True, random_state=42)
scores_nested = cross_val_score(grid_search, X, y, cv=outer_cv, scoring='accuracy')
print("Puntuación media en validación anidada:", scores_nested.mean())
Para la mayoría de proyectos, combinar un esquema de validación cruzada estratificado (o adaptado a series temporales) con la búsqueda de hiperparámetros y el uso de pipelines es suficiente para obtener resultados fiables. Sin embargo, si el conjunto de datos es muy pequeño, se pueden aplicar métodos exhaustivos como LOOCV y, si es muy grande, se suele optar por prácticas más rápidas como train_test_split
repetido con diferentes particiones.
De este modo, scikit learn aporta un marco sólido de validación que, aplicado metódicamente, evita conclusiones engañosas y permite comparar distintos modelos con rigor. La elección final de un procedimiento de validación depende de la estructura de los datos, de la métrica de interés y de los recursos computacionales disponibles. Con la variedad de herramientas que ofrece la biblioteca, cada proyecto puede configurarse para alcanzar el equilibrio justo entre eficiencia y exactitud.
Lecciones de este módulo de ScikitLearn
Lecciones de programación del módulo Validación de modelos del curso de ScikitLearn.
Ejercicios de programación en este módulo de ScikitLearn
Evalúa tus conocimientos en Validación de modelos con ejercicios de programación Validación de modelos de tipo Test, Puzzle, Código y Proyecto con VSCode.