Só pra complementar: Funções de Perda (MSE, MAE, Huber)

Esse post não vem de nenhum lab específico do curso, é um extra que a gente ganhou de tanto martelar em cima da função de custo nos posts 2 e 3. Lá atrás a gente elevou o erro ao quadrado sem questionar muito o porquê, só que "elevar ao quadrado" é uma escolha, não a única opção. Bora abrir esse leque.
Dando nome ao que você já construiu: MSE
A função de custo que você já usa desde o post 2 tem um nome oficial: (Mean Squared Error, erro quadrático médio).
Repara que é basicamente a mesma fórmula do post 2, só sem o "2" extra no denominador (aquele 2 só existia pra facilitar a derivada do gradiente descendente, lembra?). O nome muda, a essência não.
A alternativa mais direta: MAE
E se, em vez de elevar ao quadrado, a gente só pegasse o valor absoluto do erro? Essa é a (Mean Absolute Error, erro absoluto médio):
A diferença parece pequena no papel, mas muda tudo no comportamento. No MSE, errar o dobro custa quatro vezes mais (lembra do post 2?). No MAE, errar o dobro custa exatamente o dobro, nem mais, nem menos. É a diferença entre um juiz que enlouquece quando você erra feio e um juiz que só conta pontos de forma proporcional, sem drama extra.
As duas formas lado a lado
Nada de imaginar a forma, olha ela:
Repara: MSE é uma parábola (cresce cada vez mais rápido), MAE é um V (cresce sempre na mesma taxa). Segura essa imagem na cabeça, ela explica tudo que vem a seguir.
O melhor dos dois mundos: Huber
MSE é sensível demais a erro grande. MAE é durão demais, até com erro pequeno (repara no V: mesmo erros minúsculos custam proporcionalmente ao tamanho deles, sem o "desconto" que o quadrado dá perto de zero). A tenta pegar o melhor dos dois: parábola suave pertinho de zero, reta a partir de um limiar (delta).
Onde é o erro de um exemplo. Arrasta o slider do delta lá em cima de novo e observa a curva laranja: com delta pequeno, Huber vira quase um MAE, e com delta grande, vira quase um MSE. Delta é literalmente o controle de "a partir de que tamanho de erro eu paro de dar desconto".
O impacto de um outlier
Aqui é onde a escolha da função de perda deixa de ser teoria e vira decisão de verdade. Pega o dataset de 6 casas do post 2 e adiciona uma casa a mais, numa posição fixa. Você controla o preço dela com o slider, arrastando de um valor razoável até um valor bem fora da curva (um ), e observa três retas ajustadas ao vivo, uma pra cada função de perda:
- MSE: w = 207.2, b = 45.5
- MAE: w = 217.0, b = 33.0
- Huber: w = 209.6, b = 21.2
Arrasta até o valor máximo e observa: a reta azul (MSE) sai correndo atrás do ponto vermelho, se contorcendo pra tentar "agradar" o outlier. A reta verde (MAE) mal se mexe. A laranja (Huber) fica no meio do caminho. Isso não é coincidência nem só desse exemplo, é a consequência direta do gráfico das duas formas que você viu ali em cima: quadrado pune erro grande sem limite, valor absoluto não.
Fechando
| Função de perda | Fórmula | Reação a outlier | Quando usar |
|---|---|---|---|
| MSE | erro ao quadrado | sensível, se deixa puxar | dado limpo, sem outlier relevante |
| MAE | valor absoluto do erro | robusta, quase imune | dado com outlier que você quer ignorar |
| Huber | híbrida (quadrado perto de zero, reta longe) | meio-termo ajustável | quando você quer um pouco de cada, controlando via delta |
Três ideias pra levar:
- A função de perda não é um detalhe técnico escondido, é uma escolha de design que muda o comportamento do modelo inteiro, principalmente na presença de dado real e sujo.
- Elevar ao quadrado pune erro grande desproporcionalmente, é ótimo quando você confia no seu dataset, perigoso quando não confia.
- Huber existe justamente pra você não ter que escolher no escuro: o delta é um botão que desliza entre os dois extremos.
Aplicação prática
Mesmo dataset real de imóveis dos posts anteriores (Housing Prices Regression, Kaggle). Dessa vez, um cenário bem realista: um erro de digitação. Uma casa de 60 pés² (bem pequena) foi cadastrada por engano custando quase 2 milhões de dólares.
# 50 casas reais + 1 erro de digitação: 60 pés², $1.9 milhão
x_com_erro = [*x_sqft, 0.6]
y_com_erro = [*y_price, 1900]
ols = fit_mse(x_com_erro, y_com_erro) # ajuste comum (mínimos quadrados)
mae = fit_irls(x_com_erro, y_com_erro, "mae") # robusto a outlier
huber = fit_irls(x_com_erro, y_com_erro, "huber", delta=50)
casa_nova = 1.5 # 150 pés², na mesma escala dos posts anteriores
for nome, (w, b) in [("MSE", ols), ("MAE", mae), ("Huber", huber)]:
print(f"{nome}: ${(w * casa_nova + b) * 1000:,.0f}")
Saída:
MSE: $608,900/MAE: $570,700/Huber: $569,800
Sem o erro de digitação, os três dão praticamente o mesmo palpite pra essa casa (por volta de 573 mil). Com o erro de digitação, o MSE pula pra quase 35 mil só por causa de uma linha errada na planilha, enquanto MAE e Huber mal se mexem (menos de $3 mil de diferença). Testa você mesmo, arrastando o outlier:
Carregando dados reais...
Numa base de dados de verdade, com milhares de linhas, erro de digitação acontece. A escolha da função de perda decide se um erro desses vira um problema seu ou não.