Machine Learning · Insper

Validação Cruzada

Abordagem fundamental

Validação cruzada (CV, do inglês cross-validation): medir uma receita sem depender da sorte de uma divisão

O caminho desta parte

  1. Três conjuntostreino, validação, teste; por que a validação se desgasta
  2. Um split → k foldsa loteria de um split; k-fold: k partes se revezam na validação; média ± desvio
  3. Folds honestoso divisor certo, pré-processamento reajustado em cada fold
  4. A receita honestacinco regras, depois o lab: ajustar C com busca em grade
Cada etapa responde a uma pergunta: que dados podem julgar o modelo? → como escapar da sorte de um split? → o que precisa ficar separado em cada fold? → que número reportar e como?
Etapa 1 · Que dados podem julgar o modelo?

Três conjuntos, três papéis

O conjunto dividido em treino 60%, validação 20% e teste 20%, com o que cada bloco responde
treinoo modelo aprende seus parâmetros aquitocado sempre
validaçãoescolhe entre modelos e hiperparâmetrostocado muitas vezes
testesimula o futurotocado uma vez
Como você toma decisões na validação, o desempenho nela fica otimista com o tempo. Se você itera contra o teste, ele silenciosamente vira um conjunto de validação.

Por que um conjunto em que você escolhe deixa de ser honesto

Dados de puro ruído: 20 colunas aleatórias, alvo no cara ou coroa. Nenhum modelo pode passar de 50%. Treine 100 árvores com hiperparâmetros aleatórios e fique com a melhor na validação.

Preveja. O vencedor marca acima de 50% na validação. Quanto a mesma árvore marca em dados intocados? A diferença cresce ou diminui quando você compara mais configurações?

O escore de validação do melhor de K modelos sobe a 61% em puro ruído enquanto o de teste fica no acaso
O vencedor marca 61,2% na validação e 50,9% em dados intocados. Nenhum modelo melhorou: você escolheu o que por acaso combinou com as peculiaridades daquelas 100 linhas.

É a maldição do vencedor: o viés cresce com o número de coisas que você testou.

Etapa 2 · Como escapar da sorte de um split?

Um único split é uma loteria

Preveja. Só muda o random_state da divisão. Quão distantes podem ficar duas acurácias reportadas? E duas médias de uma CV 5-fold?

A acurácia hold-out vai de 93% a 100% conforme a semente; a média da CV 5-fold só de 96,8% a 98,4%

Mesmo modelo, mesmos dados, 300 sementes de uma divisão 80/20:

um hold-out93,0% a 100,0%
média da CV 5-fold96,8% a 98,4%
Um aluno que reporta 100% e outro que reporta 93% podem ter escrito código idêntico.

A CV reduz muito a sorte da divisão; ela não remove a sorte da amostra — todos os folds saem das mesmas linhas.

Simulador: a sorte da divisão

Preveja. Com \(n = 80\) linhas (\(n\) = número de linhas), aperte Sortear 100: qual faixa é mais larga, a do hold-out ou a da média da CV? Depois aperte Novo conjunto algumas vezes: a faixa da CV fica sobre a linha branca?

k-fold, passo a passo

Particione os dados de treino em \(k\) folds; cada rodada treina nos outros \(k-1\) e avalia no que ficou de fora; reporte a média e o desvio-padrão dos \(k\) escores.

k-fold no código

A CV roda só em X_train: o teste continua trancado fora, como no diagrama.


cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
scores = cross_val_score(pipe, X_train, y_train, cv=cv, scoring='f1')
print(f"{scores.mean():.3f} ± {scores.std():.3f}")
  
Toda observação valida exatamente uma vez e o modelo é avaliado em todas as linhas: é daí que vem a redução de variância. O preço são \(k\) ajustes.

A dispersão também é informação

  • Se os folds dão 0,97 · 0,96 · 0,98 · 0,71 · 0,97, a média esconde um modelo que falha feio em algum subconjunto. Aquele fold merece uma olhada.
  • Um recall de 0,95 ± 0,05 e outro de 0,95 ± 0,005 são afirmações muito diferentes.
Os \(k\) modelos são descartados. A CV avalia uma receita (algoritmo + hiperparâmetros + pré-processamento); o que vai para produção é essa receita reajustada uma vez em todos os dados de treino.
Etapa 3 · O que precisa ficar separado em cada fold?

Escolhendo um esquema de CV

Folds produzidos por KFold, StratifiedKFold, GroupKFold e TimeSeriesSplit em 60 linhas ordenadas por classe e grupo

Os divisores diferem em quais linhas podem cair juntas num fold de validação.

Qual divisor usar

métodoquando usarcuidado com
K-Foldregressão, dados balanceados (com shuffle=True)folds sem nenhuma linha de uma classe rara
Stratified K-Foldclassificação, principalmente desbalanceadasó estratifica pelo alvo
Leave-One-Outconjuntos muito pequenos\(n\) ajustes (\(n\) = número de linhas); uma linha por fold: sem desvio por fold
TimeSeriesSplitdados temporaisos primeiros folds treinam com pouco; gap se o alvo olha à frente
Group K-Folddados agrupados (pacientes, usuários)exige uma coluna de grupo

Preveja. 100 linhas, 8 positivas, KFold embaralhado em 5 folds: com que frequência algum fold fica sem nenhuma positiva?

Embaralhar não basta: com 100 linhas e 8 positivas, o KFold embaralhado deixou algum fold sem nenhuma positiva em 65% das sementes. A estratificação garante 1 ou 2 em todos.

O pré-processamento reinicia em cada fold

Preveja. Se o scaler for ajustado em todo o X antes da CV, o escore sai mais alto, mais baixo ou quase igual? E se o passo fosse um seletor de atributos que olha o y?


# ERRADO: as estatísticas das linhas de validação vazam para o treino
X_scaled = StandardScaler().fit_transform(X)
cross_val_score(LogisticRegression(), X_scaled, y, cv=cv)

# CERTO: cada fold ganha o próprio scaler
pipe = make_pipeline(StandardScaler(), LogisticRegression())
cross_val_score(pipe, X, y, cv=cv)
  
  • Escalonamento, codificação, imputação e seleção de atributos precisam ser reajustados dentro de cada fold.
  • Num Pipeline, todos os passos são ajustados só na porção de treino do fold e aplicados congelados à de validação.
Quanto custa fazer errado depende do que o passo aprende e a parte avançada mede: um scaler quase não muda nada aqui; um seletor de atributos fabrica 36 pontos do nada.
Etapa 4 · Que número reportar e como?

A receita da validação honesta

  1. Tranque o conjunto de teste, com stratify se for classificação.
  2. Troque o split pela CV: StratifiedKFold(5, shuffle=True, random_state=...).
  3. Monte cada candidato como um Pipeline, com todo passo ajustado dentro.
  4. Reporte média ± desvio e olhe os folds individuais.
  5. Reuse um único objeto cv em todos os candidatos — a comparação fica pareada.
A CV substitui o conjunto de validação, nunca o de teste.
Lab fundamental · cerca de 35 min, em duplas

Câncer de mama: a CV em ação, passos 1 a 6

  • 569 tumores, 30 medidas; a métrica é o recall da classe maligna.
  • Notebook no Colab: nada para baixar. Salve uma cópia no seu Drive.
  • Em cada passo, responda o Preveja antes de rodar.
  • Simulações: a sorte da divisão, medida (passo 4) e a regra de um erro-padrão (passo 6).

Ritmo: passos 1 a 3 em 10 min; passo 4 e a simulação em 12 min; passos 5 e 6 com a simulação em 13 min.