Data Leakage
Vazamento de Dados
O vazamento de dados é o destruidor silencioso de modelos. Ocorre quando informações de fora do conjunto de treinamento são inadvertidamente usadas para criar o modelo, fazendo-o parecer muito melhor do que realmente é. Modelos com vazamento podem alcançar acurácia de validação quase perfeita, passar em todos os testes e falhar completamente em produção.
O Vazamento de Dados é a principal causa de resultados de AM irreproduziveis
O vazamento pode ser sutil o suficiente para que praticantes experientes o ignorem. É responsável por uma parcela significativa de artigos de aprendizado de máquina retratados e implantações em produção que falharam.
Tipos de Vazamento de Dados
1. Vazamento de Alvo
Usar features que são causalmente causadas pelo alvo, não causas dele.
Exemplo: Prever se um paciente receberá prescrição do antibiótico X.
| Feature | Vazamento? | Motivo |
|---|---|---|
| Idade, pressão arterial | ✅ Não | Existem antes do diagnóstico |
Flag tomou_antibiotico_x | ❌ SIM | Causada pela prescrição |
data_visita_farmacia | ❌ SIM | Acontece após a prescrição |
pontuacao_recomendacao_medico | ❌ SIM | Faz parte da decisão |
O modelo aprende "se tomou_antibiotico_x = True, então prescrição = True" — uma regra circular e inútil.
Prevenção: Para cada feature, pergunte: "Este valor existe no momento da previsão?" Se a resposta for "às vezes" ou "depende", trate com suspeição.
2. Contaminação Treino-Teste
Permitir que informações do conjunto de teste influenciem o processo de treinamento.
A forma mais comum: ajustar um pré-processador (scaler, imputer, encoder) em todo o dataset antes da divisão.
Código errado:
# ❌ VAZAMENTO — scaler vê os dados de teste
scaler = StandardScaler()
X_all_scaled = scaler.fit_transform(X_all) # usa TODOS os dados
X_train, X_test = train_test_split(X_all_scaled)
Código correto:
# ✅ CORRETO — scaler vê apenas os dados de treino
X_train, X_test = train_test_split(X_all)
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train) # fit + transform apenas no treino
X_test = scaler.transform(X_test) # apenas transform no teste
Usando Pipelines (recomendado):
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
pipe = Pipeline([
('scaler', StandardScaler()),
('model', LogisticRegression())
])
pipe.fit(X_train, y_train) # scaler.fit é chamado apenas em X_train
pipe.score(X_test, y_test) # scaler.transform é chamado em X_test
Pipelines do Scikit-learn são a forma idiomática de prevenir contaminação treino-teste.
3. Vazamento Temporal
Em problemas de séries temporais, usar informações futuras para prever o passado.
Passado Futuro
── [x₁, x₂, x₃] ──prever──► [x₄] ──────────►
↑
NÃO deve ver x₄ durante treino para x₃!
Errado: Divisão aleatória em um dataset de série temporal.
Correto: Sempre use uma divisão temporal — todos os dados de treino vêm estritamente antes do período de validação/teste.
# ❌ Errado para séries temporais
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# ✅ Correto para séries temporais
split_idx = int(len(X) * 0.8)
X_train, X_test = X[:split_idx], X[split_idx:]
y_train, y_test = y[:split_idx], y[split_idx:]
4. Vazamento na Engenharia de Features
Calcular features que agregam informações do dataset completo — incluindo as linhas de teste.
# ❌ VAZAMENTO: estatísticas de grupo calculadas em todo o dataset
df['media_gasto_usuario'] = df.groupby('user_id')['gasto'].transform('mean')
# ✅ CORRETO: calcular no conjunto de treino, mesclar no teste
medias_treino = X_train.groupby('user_id')['gasto'].mean().rename('media_gasto_usuario')
X_train = X_train.merge(medias_treino, on='user_id', how='left')
X_test = X_test.merge(medias_treino, on='user_id', how='left') # usa stats do treino
Checklist para Detecção de Vazamento
Um Exemplo Real Famoso: o Heritage Health Prize
O Heritage Health Prize de 2011 (competição de $3M) teve várias equipes top desqualificadas por vazamento. Uma equipe atingiu AUC=0,98 na validação — muito acima do baseline humano — ao usar acidentalmente uma feature derivada da variável alvo. Quando o erro foi descoberto e a feature removida, o desempenho caiu para AUC=0,76.
A lição: resultados extraordinários exigem escrutínio extraordinário dos dados.