Entender por que um modelo que tem bom desempenho em dados de treinamento pode falhar no mundo real. Aprender a detectar, prevenir e medir o sobreajuste usando técnicas de validação robustas.
Sobreajuste ocorre quando um modelo aprende os dados de treinamento muito bem—incluindo ruído e padrões aleatórios—em vez de padrões gerais. Resultado:
Imagine um aluno que memoriza respostas de exame em vez de entender conceitos. No exame real, ele reprova.
Método mais simples: comparar desempenho em treinamento vs. validação/teste.
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
modelo = LogisticRegression()
modelo.fit(X_train, y_train)
# Desempenho em treinamento
y_train_pred = modelo.predict(X_train)
train_acc = accuracy_score(y_train, y_train_pred)
# Desempenho em teste
y_test_pred = modelo.predict(X_test)
test_acc = accuracy_score(y_test, y_test_pred)
print(f"Acurácia de Treinamento: {train_acc:.4f}")
print(f"Acurácia de Teste: {test_acc:.4f}")
# Se train_acc >> test_acc → Sobreajuste!
⚠️ Exemplo típico:
Adiciona uma penalidade à função de perda para evitar que os coeficientes fiquem muito grandes.
# Regressão logística com regularização L2 (Ridge)
modelo_l2 = LogisticRegression(penalty='l2', C=1.0) # C menor = mais regularização
# Com L1 (Lasso) para seleção automática de características
modelo_l1 = LogisticRegression(penalty='l1', solver='liblinear', C=0.1)
✅ L1 (Lasso): Pode zerar coeficientes → seleção de características.
✅ L2 (Ridge): Reduz coeficientes mas não os zera → mais estável.
Simples mas poderoso. Mais dados representativos ajudam o modelo a aprender padrões mais gerais.
A melhor ferramenta para avaliar a capacidade de generalização de um modelo antes de ver dados de teste.
Validação simples (divisão treino/teste) pode ser enganosa se a divisão for sorte ou azar.
Validação cruzada (CV) divide os dados em K dobras, treina K vezes, cada vez usando uma dobra diferente como validação.
Resultado: uma estimativa de desempenho mais robusta e confiável.
from sklearn.model_selection import cross_val_score
modelo = LogisticRegression()
# Validação cruzada de 5 dobras
scores = cross_val_score(modelo, X_train, y_train, cv=5, scoring='roc_auc')
print(f"AUC-ROC por dobra: {scores}")
print(f"AUC-ROC médio: {scores.mean():.4f} (+/- {scores.std() * 2:.4f})")
✅ Vantagens:
Divide em K partes iguais. Cada dobra é usada uma vez como validação.
from sklearn.model_selection import KFold
kf = KFold(n_splits=5, shuffle=True, random_state=42)
Mantém proporções de classes em cada dobra. ESPECIALMENTE IMPORTANTE PARA CONJUNTOS DE DADOS 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 dobra é uma única observação. Muito caro computacionalmente; apenas para conjuntos de dados muito pequenos.
import numpy as np
# Treinar e avaliar com treino/teste simples
modelo.fit(X_train, y_train)
test_score = roc_auc_score(y_test, modelo.predict_proba(X_test)[:,1])
# Avaliar com CV no conjunto de treinamento
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'Pontuação Teste: {test_score:.4f}')
plt.plot(range(1,6), cv_scores, 'bo-', label='Pontuações CV por Dobra')
plt.axhline(y=cv_scores.mean(), color='blue', linestyle='-', label=f'Média CV: {cv_scores.mean():.4f}')
plt.title("Comparação: Validação Cruzada vs Teste Final")
plt.xlabel("Dobra")
plt.ylabel("AUC-ROC")
plt.legend()
plt.grid()
plt.show()
Conjunto de dados: caracteristicas_fraude.csv (pré-processado com características selecionadas)
Tarefas:
C=0.01) e comparar.