Phase 02 - Lesson 10
Troca entre polarização e variância
This lesson includes a graded coding exercise that runs in your browser, unlocked with lifetime access.
Cada erro do modelo vem de uma de três fontes: tendência, variância ou ruído. Você só pode controlar os dois primeiros.
Tipo: Aprender Idioma: Python Pré-requisitos: Fase 2, Lições 01-09 (noções básicas de ML, regressão, classificação, avaliação) Tempo: ~75 minutos
Objetivos de aprendizagem
- Derivar a decomposição polarização-variância do erro de previsão esperado e explicar o papel do ruído irredutível
- Diagnosticar se um modelo sofre de alto viés ou alta variância usando padrões de erro de treinamento e teste
- Explicar como as técnicas de regularização (L1, L2, abandono, parada antecipada) trocam o viés pela variância
- Implementar experimentos que visualizem a compensação viés-variância entre modelos de complexidade crescente
O problema
Você treinou um modelo. Tem algum erro nos dados de teste. De onde vem esse erro?
Se o seu modelo for muito simples (regressão linear em um conjunto de dados curvo), ele perderá consistentemente o padrão verdadeiro. Isso é preconceito. Se o seu modelo for muito complexo (polinômio de grau 20 em 15 pontos de dados), ele se ajustará perfeitamente aos dados de treinamento, mas fornecerá previsões totalmente diferentes em novos dados. Isso é variação.
Você não pode minimizar ambos ao mesmo tempo para uma capacidade de modelo fixa. Empurre o viés para baixo e a variância aumentará. Empurre a variância para baixo e o viés aumentará. Compreender essa compensação é a habilidade de diagnóstico mais útil no aprendizado de máquina. Ele informa se você deve tornar seu modelo mais complexo ou menos complexo, se deve obter mais dados ou projetar recursos melhores, se deve regularizar mais ou menos.
O Conceito
Viés: erro sistemático
O viés mede o quão longe a previsão média do seu modelo está do valor real. Se você treinou o mesmo modelo em muitos conjuntos de treinamento diferentes extraídos da mesma distribuição e calculou a média das previsões, o viés é a lacuna entre essa média e a verdade.
Alto viés significa que o modelo é muito rígido para capturar o padrão real. Uma linha reta ajustada a uma parábola sempre errará a curva, não importa quantos dados você forneça. Isso é inadequado.
High bias (underfitting):
Model always predicts roughly the same wrong thing.
Training error: HIGH
Test error: HIGH
Gap between them: SMALL
Variância: Sensibilidade aos Dados de Treinamento
A variância mede o quanto suas previsões mudam quando você treina em diferentes subconjuntos de dados. Se pequenas alterações no conjunto de treinamento causarem grandes alterações no modelo, a variância será alta.
Alta variância significa que o modelo está ajustando o ruído aos dados de treinamento, não ao sinal subjacente. Um polinômio de grau 20 passará por todos os pontos de treinamento, mas oscilará descontroladamente entre eles. Isso é overfitting.
High variance (overfitting):
Model fits training data perfectly but fails on new data.
Training error: LOW
Test error: HIGH
Gap between them: LARGE
A decomposição
Para qualquer ponto x, o erro de previsão esperado sob a perda quadrática se decompõe exatamente:
Expected Error = Bias^2 + Variance + Irreducible Noise
where:
Bias^2 = (E[f_hat(x)] - f(x))^2
Variance = E[(f_hat(x) - E[f_hat(x)])^2]
Noise = E[(y - f(x))^2] (sigma^2)
f(x)é a verdadeira funçãof_hat(x)é a previsão do seu modeloE[...]é a expectativa sobre diferentes conjuntos de treinamentoyé o rótulo observado (função verdadeira mais ruído)
O termo ruído é irredutível. Nenhum modelo pode se sair melhor do que sigma^2 em dados ruidosos. Seu trabalho é encontrar o equilíbrio certo entre viés ^ 2 e variância.
Complexidade do modelo vs erro
graph LR
A[Simple Model] -->|increase complexity| B[Sweet Spot]
B -->|increase complexity| C[Complex Model]
style A fill:#f9f,stroke:#333
style B fill:#9f9,stroke:#333
style C fill:#f99,stroke:#333
A clássica curva em forma de U:
| Complexidade | Viés | Variância | Erro total |
|---|---|---|---|
| Muito baixo | ALTO | BAIXO | ALTO (ajuste insuficiente) |
| Perfeito | MODERADO | MODERADO | MAIS BAIXO |
| Muito alto | BAIXO | ALTO | ALTO (overfitting) |
Regularização como controle de polarização-variância
A regularização aumenta deliberadamente o viés para reduzir a variância. Ele restringe o modelo para que não possa perseguir ruído.
- L2 (Ridge): Reduz todos os pesos para zero. Mantém todos os recursos, mas reduz sua influência.
- L1 (Lasso): Empurra alguns pesos exatamente para zero. Executa a seleção de recursos.
- Dropout: Desativa aleatoriamente os neurônios durante o treinamento. Força representações redundantes.
- Parada antecipada: Interrompe o treinamento antes que o modelo se ajuste totalmente aos dados de treinamento.
A força de regularização (lambda, taxa de abandono, número de épocas) controla diretamente onde você se encontra na curva de polarização-variância. Mais regularização significa mais preconceito e menos variação.
Descida Dupla: A Perspectiva Moderna
A teoria clássica diz: depois do ponto ideal, mais complexidade sempre dói. Mas pesquisas desde 2019 mostraram algo inesperado. Se você continuar aumentando a capacidade do modelo além do limite de interpolação (onde o modelo tem parâmetros suficientes para ajustar perfeitamente os dados de treinamento), o erro de teste poderá diminuir novamente.
graph LR
A[Underfit Zone] --> B[Classical Sweet Spot]
B --> C[Interpolation Threshold]
C --> D[Double Descent - Error Drops Again]
style A fill:#fdd,stroke:#333
style B fill:#dfd,stroke:#333
style C fill:#fdd,stroke:#333
style D fill:#dfd,stroke:#333
Esse fenômeno de “descida dupla” explica por que redes neurais superparametrizadas (com muito mais parâmetros do que exemplos de treinamento) ainda generalizam bem. A clássica compensação entre polarização e variância não está errada, mas é incompleta para o regime moderno.
Principais observações sobre descida dupla:
- Acontece em modelos lineares, árvores de decisão e redes neurais
- Mais dados podem realmente prejudicar a região de interpolação (dupla descida amostral)
- Mais épocas de treinamento também podem causar isso (descida dupla por época)
- A regularização suaviza o pico, mas não o elimina
Por que isso acontece? No limite de interpolação, o modelo tem capacidade suficiente para ajustar todos os pontos de treinamento. Ele é forçado a uma solução muito específica que passa por todos os pontos, e pequenas perturbações nos dados causam grandes mudanças no ajuste. É aqui que a variância atinge o pico. Passado o limite, o modelo tem muitas soluções possíveis que se ajustam perfeitamente aos dados. O algoritmo de aprendizagem (por exemplo, gradiente descendente com regularização implícita) tende a escolher o mais simples entre eles. Essa tendência implícita em direção a soluções simples é a razão pela qual os modelos superparametrizados generalizam.
| Regime | Parâmetros vs Amostras | Comportamento |
|---|---|---|
| Subparametrizado | p << n | A compensação clássica se aplica |
| Limiar de interpolação | p ~ n | Picos de variância, picos de erros de teste |
| Sobreparametrizado | p >> n | A regularização implícita entra em ação, o erro de teste cai |
Para fins práticos: se você estiver usando redes neurais ou grandes conjuntos de árvores, não pare no limite de interpolação. Fique bem abaixo dele (com regularização explícita) ou ultrapasse-o. O pior lugar para se estar é bem no limiar.
Diagnosticando seu modelo
flowchart TD
A[Compare train error vs test error] --> B{Large gap?}
B -->|Yes| C[High variance - overfitting]
B -->|No| D{Both errors high?}
D -->|Yes| E[High bias - underfitting]
D -->|No| F[Good fit]
C --> G[More data / Regularize / Simpler model]
E --> H[More features / Complex model / Less regularization]
F --> I[Deploy]
| Sintoma | Diagnóstico | Correção |
|---|---|---|
| Erro de trem alto, erro de teste alto | Viés | Mais funcionalidades, modelo complexo, menos regularização |
| Erro de trem baixo, erro de teste alto | Variância | Mais dados, regularização, modelo mais simples, abandono |
| Erro de trem baixo, erro de teste baixo | Bom ajuste | Envie |
| Erro de trem diminuindo, erro de teste aumentando | Overfitting em andamento | Paragem antecipada |
Estratégias Práticas
Quando o preconceito é o problema:
- Adicione recursos polinomiais ou de interação
- Use um modelo mais flexível (conjunto de árvores em vez de linear)
- Reduzir a força de regularização
- Treine por mais tempo (se ainda não convergiu)
Quando a variação é o problema:
- Obtenha mais dados de treinamento
- Use ensacamento (florestas aleatórias)
- Aumentar a regularização (maior lambda, mais abandono)
- Seleção de recursos (remover recursos barulhentos)
- Use validação cruzada para detectá-lo precocemente
Métodos de conjunto e redução de variância
Os métodos de conjunto são a ferramenta mais prática para combater a variação.
Bagging (Agregação de Bootstrap) treina vários modelos em diferentes amostras de bootstrap dos dados de treinamento e, em seguida, calcula a média de suas previsões. Cada modelo individual tem alta variância, mas a média tem variância muito menor. As florestas aleatórias são ensacadas aplicadas às árvores de decisão.
Por que funciona matematicamente: se você calcular a média de N previsões independentes, cada uma com variância sigma ^ 2, a variância da média será sigma ^ 2 / N. Os modelos não são verdadeiramente independentes (todos veem dados semelhantes), portanto a redução é menor que 1/N, mas ainda é substancial.
Boosting reduz o viés construindo modelos sequencialmente, onde cada novo modelo se concentra nos erros do conjunto até o momento. O aumento de gradiente e AdaBoost são os principais exemplos. Boosting pode ajustar demais se você adicionar muitos modelos, então você precisa de uma parada ou regularização antecipada.
| Método | Efeito Primário | Mudança de preconceito | Mudança de Variância |
|---|---|---|---|
| Bagging | Reduz a variação | Sem alterações | Diminui |
| Boosting | Reduz preconceito | Diminui | Pode aumentar |
| Empilhamento | Reduz ambos | Depende do meta-aluno | Depende dos modelos básicos |
| Abandono | Ensacamento implícito | Ligeiro aumento | Diminui |
Regra prática: se o seu modelo base tiver alta variância (árvores profundas, polinômios de alto grau), use bagging. Se o seu modelo básico tiver viés alto (tocos rasos, modelos lineares simples), use o reforço.
Curvas de aprendizagem
As curvas de aprendizado representam erros de treinamento e validação em função do tamanho do conjunto de treinamento. Eles são a ferramenta de diagnóstico mais prática que você possui. Ao contrário de uma única comparação de treinamento/teste, as curvas de aprendizado mostram a trajetória do seu modelo e informam se mais dados ajudarão.
flowchart TD
subgraph HB["High Bias Learning Curve"]
direction LR
HB1["Small N: both errors high"]
HB2["Large N: both errors converge to HIGH error"]
HB1 --> HB2
end
subgraph HV["High Variance Learning Curve"]
direction LR
HV1["Small N: train low, test high (big gap)"]
HV2["Large N: gap shrinks but slowly"]
HV1 --> HV2
end
subgraph GF["Good Fit Learning Curve"]
direction LR
GF1["Small N: some gap"]
GF2["Large N: both converge to LOW error"]
GF1 --> GF2
end
Como lê-los:
| Cenário | Erro de treinamento | Erro de validação | Lacuna | O que isso significa | O que fazer |
|---|---|---|---|---|---|
| Viés elevado | Alto | Alto | Pequeno | O modelo não consegue capturar o padrão | Mais funcionalidades, modelo complexo, menos regularização |
| Alta variação | Baixo | Alto | Grande | Modelo memoriza dados de treinamento | Mais dados, regularização, modelo mais simples |
| Bom ajuste | Moderado | Moderado | Pequeno | Modelo generaliza bem | Envie |
| Alta variação, melhorando | Baixo | Diminuindo com mais dados | Encolhendo | Problema de variação que os dados podem resolver | Colete mais dados |
| Viés alto, plano | Alto | Alto e plano | Pequeno e plano | Mais dados NÃO ajudarão | Alterar arquitetura do modelo |
O insight crítico: se ambas as curvas estagnaram e a lacuna for pequena, mas ambos os erros forem altos, mais dados serão inúteis. Você precisa de um modelo melhor. Se a lacuna for grande e ainda estiver diminuindo, mais dados serão úteis.
Como gerar curvas de aprendizagem
Existem duas abordagens:
Abordagem 1: variar o tamanho do conjunto de treinamento, modelo fixo. Mantenha o modelo e os hiperparâmetros constantes. Treine em subconjuntos cada vez maiores de dados de treinamento. Meça o erro de treinamento e o erro de validação em cada tamanho. Esta é a curva de aprendizado padrão.
Abordagem 2: Variar a complexidade do modelo, dados fixos. Mantenha os dados constantes. Varrer um parâmetro de complexidade (grau polinomial, profundidade da árvore, número de camadas). Meça o erro de treinamento e o erro de validação em cada complexidade. Esta é uma curva de validação e mostra diretamente a compensação entre viés e variância.
Ambas as abordagens se complementam. A primeira informa se mais dados ajudarão. A segunda informa se um modelo diferente ajudará. Execute ambos antes de tomar decisões sobre sua próxima etapa.
flowchart TD
A[Model underperforming] --> B[Generate learning curve]
B --> C{Gap between train and val?}
C -->|Large gap, val still decreasing| D[More data will help]
C -->|Small gap, both high| E[More data will NOT help]
C -->|Large gap, val flat| F[Regularize or simplify]
E --> G[Generate validation curve]
G --> H[Try more complex model]
Construa
O código em code/bias_variance.py executa o experimento completo de decomposição de polarização-variância. Aqui está a abordagem, passo a passo.
Etapa 1: gerar dados sintéticos a partir de uma função conhecida
Usamos f(x) = sin(1.5x) + 0.5x com ruído gaussiano. Conhecer a função verdadeira nos permite calcular o viés e a variância exatos.
def true_function(x):
return np.sin(1.5 * x) + 0.5 * x
def generate_data(n_samples=30, noise_std=0.5, x_range=(-3, 3), seed=None):
rng = np.random.RandomState(seed)
x = rng.uniform(x_range[0], x_range[1], n_samples)
y = true_function(x) + rng.normal(0, noise_std, n_samples)
return x, y
Etapa 2: Amostragem Bootstrap e Ajuste Polinomial
Para cada grau polinomial, desenhamos muitos conjuntos de treinamento de bootstrap, ajustamos o polinômio e registramos as previsões em uma grade de teste fixa. Isso nos dá uma distribuição de previsões em cada ponto de teste.
def fit_polynomial(x_train, y_train, degree, lam=0.0):
X = np.column_stack([x_train ** d for d in range(degree + 1)])
if lam > 0:
penalty = lam * np.eye(X.shape[1])
penalty[0, 0] = 0
w = np.linalg.solve(X.T @ X + penalty, X.T @ y_train)
else:
w = np.linalg.lstsq(X, y_train, rcond=None)[0]
return w
Cabemos em 200 amostras de bootstrap diferentes. Cada amostra de bootstrap é extraída da mesma distribuição subjacente, mas contém pontos diferentes.
Etapa 3: Viés de computação ^ 2, decomposição de variância
Com 200 conjuntos de previsões em cada ponto de teste, podemos calcular a decomposição diretamente a partir da definição:
mean_pred = predictions.mean(axis=0)
bias_sq = np.mean((mean_pred - y_true) ** 2)
variance = np.mean(predictions.var(axis=0))
total_error = np.mean(np.mean((predictions - y_true) ** 2, axis=1))
mean_predé E[f_hat(x)] estimado a partir de amostras de bootstrapbias_sqé a lacuna quadrada entre a previsão média e a verdadevarianceé a distribuição média de previsões entre amostras de bootstraptotal_errordeve ser aproximadamente igual ao viés ^ 2 + variância + ruído
Etapa 4: Curvas de aprendizagem
As curvas de aprendizado varrem o tamanho do conjunto de treinamento enquanto mantêm fixa a complexidade do modelo. Eles mostram se o seu modelo é limitado por dados ou por capacidade.
def demo_learning_curves():
sizes = [10, 15, 20, 30, 50, 75, 100, 150, 200, 300]
degree = 5
for n in sizes:
train_errors = []
test_errors = []
for seed in range(50):
x_train, y_train = generate_data(n_samples=n, seed=seed * 100)
w = fit_polynomial(x_train, y_train, degree)
train_pred = predict_polynomial(x_train, w)
train_mse = np.mean((train_pred - y_train) ** 2)
test_pred = predict_polynomial(x_test, w)
test_mse = np.mean((test_pred - y_test) ** 2)
train_errors.append(train_mse)
test_errors.append(test_mse)
# Average over runs gives the learning curve point
Para um modelo de alta variância (grau 5 com dados pequenos), você vê:
- O erro de treinamento começa baixo e aumenta à medida que mais dados dificultam a memorização
- O erro do teste começa alto e diminui à medida que o modelo recebe mais sinal
- A lacuna diminui com mais dados
Para um modelo de alto viés (grau 1), ambos os erros convergem rapidamente para o mesmo valor alto e mais dados não ajudam.
Etapa 5: varredura de regularização
O código também inclui demo_regularization_sweep(), que fixa um polinômio de alto grau (grau 15) e varre a força de regularização Ridge de 0,001 a 100. Isso mostra a compensação entre polarização e variância de um ângulo diferente: em vez de variar a complexidade do modelo, variamos a força da restrição.
def demo_regularization_sweep():
alphas = [0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1.0, 5.0, 10.0, 50.0, 100.0]
for alpha in alphas:
results = bias_variance_decomposition([15], lam=alpha)
r = results[15]
print(f"alpha={alpha:.3f} bias={r['bias_sq']:.4f} var={r['variance']:.4f}")
Em alfa baixo, o polinômio de grau 15 é quase irrestrito. A variância domina porque o modelo persegue o ruído em cada amostra de bootstrap. Em alfa alto, a penalidade é tão forte que o modelo efetivamente se torna uma função quase constante. O preconceito domina. O alfa ideal fica entre esses extremos.
Esta é a mesma curva U de graus polinomiais variados, mas controlada por um botão contínuo em vez de um botão discreto. Na prática, a regularização é a forma preferida de controlar a compensação porque permite um controle refinado sem alterar o conjunto de recursos.
Use-o
sklearn fornece learning_curve e validation_curve para automatizar esses diagnósticos sem escrever loops de bootstrap.
Curva de validação: complexidade do modelo de varredura
from sklearn.model_selection import validation_curve
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import Ridge
degrees = list(range(1, 16))
train_scores_all = []
val_scores_all = []
for d in degrees:
pipe = make_pipeline(PolynomialFeatures(d), Ridge(alpha=0.01))
train_scores, val_scores = validation_curve(
pipe, X, y, param_name="polynomialfeatures__degree",
param_range=[d], cv=5, scoring="neg_mean_squared_error"
)
train_scores_all.append(-train_scores.mean())
val_scores_all.append(-val_scores.mean())
Isso fornece diretamente a curva de compensação entre polarização e variância. Onde a pontuação de validação é pior em relação à pontuação do trem, a variância domina. Onde ambos são ruins, o preconceito domina.
Curva de aprendizado: tamanho do conjunto de treinamento de varredura
from sklearn.model_selection import learning_curve
pipe = make_pipeline(PolynomialFeatures(5), Ridge(alpha=0.01))
train_sizes, train_scores, val_scores = learning_curve(
pipe, X, y, train_sizes=np.linspace(0.1, 1.0, 10),
cv=5, scoring="neg_mean_squared_error"
)
train_mse = -train_scores.mean(axis=1)
val_mse = -val_scores.mean(axis=1)
Plote train_mse e val_mse contra train_sizes. A forma diz tudo sobre o seu modelo.
Validação cruzada com varredura de regularização
from sklearn.model_selection import cross_val_score
alphas = [0.001, 0.01, 0.1, 1.0, 10.0, 100.0]
for alpha in alphas:
pipe = make_pipeline(PolynomialFeatures(10), Ridge(alpha=alpha))
scores = cross_val_score(pipe, X, y, cv=5, scoring="neg_mean_squared_error")
print(f"alpha={alpha:>7.3f} MSE={-scores.mean():.4f} +/- {scores.std():.4f}")
Isso varre a força da regularização para uma complexidade fixa do modelo. Você verá a mesma compensação entre viés e variância: alfa baixo significa alta variância, alfa alto significa viés alto.
Juntando tudo: um fluxo de trabalho de diagnóstico completo
Na prática, você executa estes diagnósticos em sequência:
- Treine seu modelo. Calcule o erro de treinamento e teste.
- Se ambos forem altos: você tem um problema de preconceito. Pule para a etapa 4.
- Se o trem estiver baixo, mas o teste estiver alto: você tem um problema de variância. Gere uma curva de aprendizado para ver se mais dados ajudarão. Se não, regularize.
- Gere uma curva de validação abrangendo seu principal parâmetro de complexidade. Encontre o ponto ideal.
- No ponto ideal, gere uma curva de aprendizado. Se a lacuna ainda for grande, serão necessários mais dados ou regularização.
- Experimente Ridge/Lasso com diferentes valores alfa usando
cross_val_score. Escolha o alfa onde o erro de validação cruzada é menor.
Isso leva de 10 a 15 minutos de computação para a maioria dos conjuntos de dados tabulares e economiza horas de adivinhação.
Envie
Esta lição produz: outputs/prompt-model-diagnostics.md
Exercícios
Execute a decomposição com
noise_std=0(sem ruído). O que acontece com o termo de erro irredutível? A complexidade ideal muda?Aumente o tamanho do conjunto de treinamento de 30 para 300. Como isso afeta o componente de variação? O grau polinomial ideal muda?
Adicione regularização L2 (regressão Ridge) ao experimento. Para um polinômio fixo de alto grau (grau 15), varra lambda de 0 a 100. Trace o viés ^ 2 e a variância como funções de lambda.
Modifique a função verdadeira de um polinômio para
sin(x). Como a decomposição da polarização-variância muda? Ainda existe um grau ideal claro?Implemente um wrapper de agregação (bagging) de bootstrap simples: treine 10 modelos em amostras de bootstrap e previsões médias. Mostre que isso reduz a variância sem aumentar muito o viés.
Termos-chave
| Prazo | O que as pessoas dizem | O que isso realmente significa |
|---|---|---|
| Viés | “O modelo é muito simples” | Erro sistemático de suposições erradas. A lacuna entre a previsão média do modelo e a verdade. |
| Variância | “O modelo está superajustado” | Erro de sensibilidade aos dados de treinamento. O quanto as previsões mudam em diferentes conjuntos de treinamento. |
| Erro irredutível | “Ruído nos dados” | Erro de aleatoriedade no verdadeiro processo de geração de dados. Nenhum modelo pode eliminá-lo. |
| Subajuste | “Não aprendendo o suficiente” | O modelo tem alto viés. Ele perde o padrão real mesmo nos dados de treinamento. |
| Sobreajuste | “Memorizando os dados” | O modelo tem alta variância. Ele ajusta ruído em dados de treinamento que não generalizam. |
| Regularização | “Restringindo o modelo” | Adicionando uma penalidade para reduzir a complexidade do modelo, negociando viés para menor variância. |
| Descida dupla | “Mais parâmetros podem ajudar” | O erro de teste diminui novamente quando a capacidade do modelo excede em muito o limite de interpolação. |
| Complexidade do modelo | “Quão flexível é o modelo” | A capacidade de um modelo de se ajustar a padrões arbitrários. Controlado por arquitetura, recursos ou regularização. |
Leitura Adicional
- Hastie, Tibshirani, Friedman: Elementos de Aprendizagem Estatística, cap. 7 - o tratamento definitivo da decomposição de viés-variância
- Belkin et al., Reconciliando a prática moderna de aprendizado de máquina e o trade-off de viés-variância (2019) - o artigo de dupla descendência
- Nakkiran et al., Deep Double Descent (2019) - descida dupla por época e por amostra
- Scott Fortmann-Roe: Compreendendo a compensação entre polarização e variância - explicação visual clara