Entender por qué un modelo que funciona bien en datos de entrenamiento puede fallar en el mundo real. Aprender a detectar, prevenir y medir el sobreajuste usando técnicas de validación robustas.
Sobreajuste ocurre cuando un modelo aprende demasiado bien los datos de entrenamiento—incluyendo ruido y patrones aleatorios—en lugar de patrones generales. Resultado:
Imagina un estudiante que memoriza las respuestas del examen en lugar de entender los conceptos. En el examen real, reprueba.
Método más simple: comparar el rendimiento en entrenamiento vs. validación/test.
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
modelo = LogisticRegression()
modelo.fit(X_train, y_train)
# Rendimiento en entrenamiento
y_train_pred = modelo.predict(X_train)
train_acc = accuracy_score(y_train, y_train_pred)
# Rendimiento en test
y_test_pred = modelo.predict(X_test)
test_acc = accuracy_score(y_test, y_test_pred)
print(f"Precisión en Entrenamiento: {train_acc:.4f}")
print(f"Precisión en Test: {test_acc:.4f}")
# Si train_acc >> test_acc → ¡Sobreajuste!
⚠️ Ejemplo típico:
Agrega una penalización a la función de pérdida para evitar que los coeficientes sean demasiado grandes.
# Regresión logística con regularización L2 (Ridge)
modelo_l2 = LogisticRegression(penalty='l2', C=1.0) # C menor = más regularización
# Con L1 (Lasso) para selección automática de características
modelo_l1 = LogisticRegression(penalty='l1', solver='liblinear', C=0.1)
✅ L1 (Lasso): Puede anular coeficientes → selección de características.
✅ L2 (Ridge): Reduce coeficientes pero no los anula → más estable.
Simple pero poderoso. Más datos representativos ayudan al modelo a aprender patrones más generales.
La mejor herramienta para evaluar la capacidad de generalización de un modelo antes de ver los datos de test.
La validación simple (división train/test) puede ser engañosa si la división es afortunada o desafortunada.
Validación cruzada (CV) divide los datos en K pliegues, entrena K veces, cada vez usando un pliegue diferente como validación.
Resultado: una estimación de rendimiento más robusta y confiable.
from sklearn.model_selection import cross_val_score
modelo = LogisticRegression()
# Validación cruzada de 5 pliegues
scores = cross_val_score(modelo, X_train, y_train, cv=5, scoring='roc_auc')
print(f"AUC-ROC por pliegue: {scores}")
print(f"AUC-ROC promedio: {scores.mean():.4f} (+/- {scores.std() * 2:.4f})")
✅ Ventajas:
Divide en K partes iguales. Cada pliegue se usa una vez como validación.
from sklearn.model_selection import KFold
kf = KFold(n_splits=5, shuffle=True, random_state=42)
Mantiene las proporciones de clase en cada pliegue. ESPECIALMENTE IMPORTANTE PARA CONJUNTOS DE DATOS DESBALANCEADOS.
from sklearn.model_selection import StratifiedKFold
skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
scores = cross_val_score(modelo, X_train, y_train, cv=skf, scoring='roc_auc')
Cada pliegue es una sola observación. Muy costoso computacionalmente; solo para conjuntos de datos muy pequeños.
import numpy as np
# Entrenar y evaluar con train/test simple
modelo.fit(X_train, y_train)
test_score = roc_auc_score(y_test, modelo.predict_proba(X_test)[:,1])
# Evaluar con CV en conjunto de entrenamiento
cv_scores = cross_val_score(modelo, X_train, y_train, cv=5, scoring='roc_auc')
plt.figure(figsize=(8,5))
plt.axhline(y=test_score, color='red', linestyle='--', label=f'Puntaje Test: {test_score:.4f}')
plt.plot(range(1,6), cv_scores, 'bo-', label='Puntajes CV por Pliegue')
plt.axhline(y=cv_scores.mean(), color='blue', linestyle='-', label=f'Promedio CV: {cv_scores.mean():.4f}')
plt.title("Comparación: Validación Cruzada vs Test Final")
plt.xlabel("Pliegue")
plt.ylabel("AUC-ROC")
plt.legend()
plt.grid()
plt.show()
Conjunto de datos: fraud_features.csv (preprocesado con características seleccionadas)
Tareas:
C=0.01) y comparar.