Regressão Múltipla
Aprenda como funciona a regressão linear múltipla, interprete coeficientes, trate multicolinearidade e construa um modelo completo em Python com scikit-learn.
A regressão linear múltipla estende a regressão linear simples para usar duas ou mais variáveis independentes na previsão de um alvo contínuo. Em vez de traçar uma linha em duas dimensões, o modelo ajusta um hiperplano através de tantas dimensões quantas forem as características. Compreender como os coeficientes interagem — e quando eles podem enganar — é a habilidade central que esta página ensina.
Esta página aborda:
- A equação de regressão múltipla e o que cada coeficiente significa
- Como construir um pipeline completo com scikit-learn: carregar, pré-processar, treinar, avaliar
- Por que o escalonamento de características é importante e como fazê-lo corretamente
- Como interpretar e comparar coeficientes escalonados e não escalonados
- Diagnosticar multicolinearidade — o problema mais comum na regressão múltipla
- Análise de resíduos para verificar as suposições do modelo
- Quando escolher a regressão múltipla e o que tentar quando ela não é suficiente
A Equação da Regressão Múltipla
A regressão linear múltipla modela o alvo y como uma combinação linear de n características de entrada:
y = β₀ + β₁x₁ + β₂x₂ + ... + βₙxₙ + εβ₀— o intercepto: o valor previsto deyquando todas as características são iguais a zeroβ₁ … βₙ— os coeficientes: quantoymuda para um aumento de uma unidade em cadaxᵢ, mantendo todas as outras características constantesε— o termo de erro: a parte deyque o modelo não consegue explicar
O algoritmo encontra os coeficientes minimizando a soma dos quadrados dos resíduos (mínimos quadrados ordinários):
SSR = Σ(yᵢ - ŷᵢ)²Isso tem uma solução analítica exata em forma fechada, portanto o LinearRegression do scikit-learn não precisa de descida de gradiente iterativa — o treinamento é quase instantâneo mesmo em conjuntos de dados com centenas de milhares de linhas.
Diferença em Relação à Regressão Linear Simples
A regressão linear simples usa uma característica. A regressão múltipla adiciona mais características para que cada coeficiente capture o efeito parcial dessa característica — seu impacto no alvo enquanto as demais características permanecem constantes. Isso é mais poderoso, mas introduz novos riscos, especialmente a multicolinearidade (veja Diagnosticando a Multicolinearidade).
O Conjunto de Dados
Os exemplos abaixo utilizam o conjunto de dados California Housing integrado ao scikit-learn. Ele registra estatísticas habitacionais em nível de bloco censitário para a Califórnia em 1990 e possui 20.640 amostras com 8 características.
import pandas as pd
from sklearn.datasets import fetch_california_housing
housing = fetch_california_housing()
df = pd.DataFrame(housing.data, columns=housing.feature_names)
df['MedHouseVal'] = housing.target # median house value in $100,000s
print(df.shape) # (20640, 9)
print(df.head())As 8 características de entrada são:
| Característica | Descrição |
|---|---|
MedInc | Renda mediana no bloco (em dezenas de milhares de dólares) |
HouseAge | Idade mediana das casas no bloco |
AveRooms | Número médio de cômodos por domicílio |
AveBedrms | Número médio de quartos por domicílio |
Population | População do bloco |
AveOccup | Ocupação média por domicílio |
Latitude | Latitude do bloco |
Longitude | Longitude do bloco |
O alvo MedHouseVal é o valor mediano das casas em unidades de $100.000, portanto um valor de 2.0 representa $200.000.
Construindo o Modelo Passo a Passo
Passo 1 — Dividir os Dados
Sempre divida os dados antes de qualquer pré-processamento. Ajustar um escalonador no conjunto de dados completo vazaria as estatísticas do conjunto de teste para o treinamento, fornecendo uma avaliação excessivamente otimista. Veja Divisão Treino/Teste para uma explicação completa.
from sklearn.model_selection import train_test_split
X = df[housing.feature_names]
y = df['MedHouseVal']
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
print(f"Training samples: {len(X_train)}") # 16512
print(f"Test samples: {len(X_test)}") # 4128Passo 2 — Escalonar as Características
Os coeficientes da regressão múltipla refletem as unidades de cada característica. MedInc é medida em dezenas de milhares de dólares; Population é uma contagem bruta que pode chegar a 35.000. Sem escalonamento, o coeficiente de Population será pequeno não porque a população seja irrelevante, mas porque sua unidade é pequena.
O StandardScaler transforma cada característica para ter média zero e desvio padrão unitário, tornando as magnitudes dos coeficientes diretamente comparáveis. Veja Escalonamento de Características para detalhes sobre os escalonadores disponíveis.
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train) # fit ONLY on training data
X_test_scaled = scaler.transform(X_test) # apply the same transformationA regra crítica: chame fit_transform nos dados de treinamento e transform (sem ajuste) nos dados de teste. Ajustar nos dados de teste contaminaria a avaliação.
Passo 3 — Treinar o Modelo
from sklearn.linear_model import LinearRegression
model = LinearRegression()
model.fit(X_train_scaled, y_train)LinearRegression.fit() resolve o problema de MQO analiticamente. Não há hiperparâmetros a ajustar na regressão múltipla simples — o que você escolhe é quais características incluir.
Passo 4 — Avaliar o Modelo
import numpy as np
from sklearn.metrics import mean_squared_error, r2_score
y_pred = model.predict(X_test_scaled)
mse = mean_squared_error(y_test, y_pred)
rmse = np.sqrt(mse)
r2 = r2_score(y_test, y_pred)
print(f"Mean Squared Error: {mse:.4f}")
print(f"Root Mean Squared Error: {rmse:.4f} (±${rmse * 100_000:,.0f})")
print(f"R-squared: {r2:.4f}")Saída esperada:
Mean Squared Error: 0.5559
Root Mean Squared Error: 0.7456 (±$74,558)
R-squared: 0.5758O que as métricas significam:
- MSE (Erro Quadrático Médio) — média das diferenças ao quadrado entre previsões e valores reais. O quadrado penaliza erros grandes mais do que erros pequenos. As unidades são o quadrado do alvo ($100.000²), portanto é mais difícil de interpretar diretamente.
- RMSE (Raiz do Erro Quadrático Médio) — a raiz quadrada do MSE, de volta nas mesmas unidades do alvo. Um RMSE de 0,75 significa que as previsões do modelo diferem em cerca de $75.000 em média.
- R² (coeficiente de determinação) — a fração da variância no alvo que o modelo explica. Um R² de 0,58 significa que o modelo captura 58% da variação nos preços das casas. Os valores variam de 0 (não melhor do que prever a média) a 1 (previsões perfeitas). R² negativo é possível se o modelo for pior do que a média — isso é um forte sinal de que algo está errado.
Um R² de ~0,58 é típico para este conjunto de dados com regressão linear simples. A relação entre preços de casas e essas características é parcialmente não linear e envolve agrupamento geográfico que um hiperplano não consegue capturar bem. Algoritmos como árvores com gradiente boosting atingem rotineiramente 0,80+ neste conjunto de dados.
Passo 5 — Inspecionar os Coeficientes
Após o escalonamento, as magnitudes dos coeficientes são diretamente comparáveis — elas mostram quais características influenciam mais fortemente a previsão:
coef_df = pd.DataFrame({
'Feature': housing.feature_names,
'Coefficient': model.coef_
}).sort_values('Coefficient', key=abs, ascending=False)
print(coef_df.to_string(index=False))
print(f"\nIntercept: {model.intercept_:.4f}")Saída esperada:
Feature Coefficient
Latitude -0.8969
Longitude -0.8698
MedInc 0.8544
AveBedrms 0.3393
AveRooms -0.2944
HouseAge 0.1225
AveOccup -0.0408
Population -0.0023
Intercept: 2.0719Lendo os coeficientes após o escalonamento padrão:
MedInc = 0.854— o preditor mais forte isolado. Um aumento de um desvio padrão na renda mediana prevê um aumento de $85.400 no valor da casa, mantendo tudo o mais constante.Latitude = -0.897eLongitude = -0.869— o modelo aprendeu que blocos censitários mais ao norte e mais a leste tendem a ser mais baratos. No entanto, essas duas características geográficas são altamente correlacionadas (r = -0,93), o que pode tornar seus coeficientes individuais instáveis (veja Diagnosticando a Multicolinearidade).AveBedrms = +0.339vsAveRooms = -0.294— estes têm sinais opostos, mesmo que mais cômodos e mais quartos geralmente signifiquem casas maiores e mais caras. Este é um sinal clássico de multicolinearidade:AveRoomseAveBedrmssão correlacionadas (r = 0,85), portanto seus coeficientes se compensam mutuamente. Não os interprete isoladamente.Population = -0.002— muito próximo de zero após o escalonamento. A população do bloco tem poder preditivo mínimo quando as outras características são levadas em conta.
O intercepto (2,07) é o MedHouseVal previsto quando todas as características escalonadas são zero — ou seja, quando todas as características estão na sua média do conjunto de treinamento. Ele é igual à média dos alvos de treinamento e não tem significado de negócio direto além disso.
Passo 6 — Fazer Previsões em Novos Dados
# A new census block: high income, older house, San Francisco Bay Area
new_block = pd.DataFrame([[8.0, 41.0, 6.0, 1.0, 322, 2.5, 37.88, -122.23]],
columns=housing.feature_names)
new_block_scaled = scaler.transform(new_block)
prediction = model.predict(new_block_scaled)
print(f"Predicted median house value: ${prediction[0] * 100_000:,.0f}")Saída esperada:
Predicted median house value: $410,895O escalonador deve ser o mesmo escalonador ajustado nos dados de treinamento. Nunca reajuste o escalonador nos novos dados — isso deslocaria as entradas em relação ao que o modelo aprendeu.
Diagnosticando a Multicolinearidade
A multicolinearidade ocorre quando duas ou mais variáveis independentes são altamente correlacionadas entre si. Isso não impede o modelo de fazer previsões precisas, mas torna os coeficientes individuais não confiáveis e difíceis de interpretar. Os coeficientes podem se tornar grandes, mudar de sinal ou tornar-se estatisticamente insignificantes mesmo para características genuinamente importantes.
Verificando com uma Matriz de Correlação
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
corr = df[housing.feature_names].corr()
print(corr.round(2))Pares principais a observar:
| Par de características | Correlação | Preocupação |
|---|---|---|
AveRooms / AveBedrms | 0,85 | Alta — coeficientes se compensam mutuamente |
Latitude / Longitude | -0,93 | Muito alta — covariação geográfica |
MedInc / MedHouseVal (alvo) | 0,69 | Bom preditor, não é um problema de colinearidade |
Uma correlação acima de 0,80 entre duas características é um sinal de alerta. Ao identificá-la, considere:
- Remover uma das características correlacionadas. Se
AveRoomseAveBedrmsestão ambas no modelo, tente removerAveBedrmse verifique se o desempenho preditivo do modelo muda muito. - Combiná-las. Crie uma característica derivada (por exemplo,
rooms_per_bedroom = AveRooms / AveBedrms) que capture a relação sem redundância. - Usar um modelo regularizado. A regressão Ridge adiciona uma penalidade L2 que encolhe os coeficientes correlacionados entre si, estabilizando-os. O Lasso (L1) pode zerar características redundantes completamente.
Análise de Resíduos
Um resíduo é a diferença entre um valor real e a previsão do modelo: residual = y_actual - y_predicted. Plotar os resíduos revela se as suposições do modelo são válidas.
residuals = y_test - y_pred
print(f"Mean of residuals: {residuals.mean():.4f}") # should be close to 0
print(f"Std of residuals: {residuals.std():.4f}")Saída esperada:
Mean of residuals: 0.0035
Std of residuals: 0.7457A média está próxima de zero — um sinal de que o modelo é imparcial em média. Mas o desvio padrão de 0,75 (±$75.000) mostra dispersão substancial.
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
fig, axes = plt.subplots(1, 2, figsize=(12, 4))
# Predicted vs Actual
axes[0].scatter(y_test, y_pred, alpha=0.2, s=8)
axes[0].plot([0, 5], [0, 5], 'r--')
axes[0].set_xlabel('Actual')
axes[0].set_ylabel('Predicted')
axes[0].set_title('Predicted vs Actual')
# Residuals vs Predicted
axes[1].scatter(y_pred, residuals, alpha=0.2, s=8)
axes[1].axhline(0, color='r', linestyle='--')
axes[1].set_xlabel('Predicted')
axes[1].set_ylabel('Residual')
axes[1].set_title('Residuals vs Predicted')
plt.tight_layout()
plt.savefig('residuals.png', dpi=120)
print("Saved residuals.png")O que observar:
- Previsto vs Real — idealmente, os pontos se distribuem ao longo da diagonal. Desvio sistemático da diagonal (uma curva ou um achatamento em valores altos) indica que a suposição linear está errada para parte do intervalo.
- Resíduos vs Previsto — idealmente, os resíduos se dispersam aleatoriamente em torno de zero em todos os níveis de previsão. Uma forma de funil (maior dispersão em previsões mais altas) sinaliza heterocedasticidade — o erro do modelo não é constante, o que pode tornar as estimativas de intervalo não confiáveis.
- Agrupamentos — grupos distintos no gráfico de resíduos podem revelar que o conjunto de dados contém subpopulações (por exemplo, urbano vs rural) que justificam modelos separados ou características adicionais.
Pipeline Completo
Aqui está tudo o que foi apresentado acima como um script executável único:
import numpy as np
import pandas as pd
from sklearn.datasets import fetch_california_housing
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import mean_squared_error, r2_score
# 1. Load data
housing = fetch_california_housing()
df = pd.DataFrame(housing.data, columns=housing.feature_names)
df['MedHouseVal'] = housing.target
# 2. Split — before any preprocessing
X = df[housing.feature_names]
y = df['MedHouseVal']
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
# 3. Scale
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)
# 4. Train
model = LinearRegression()
model.fit(X_train_scaled, y_train)
# 5. Evaluate
y_pred = model.predict(X_test_scaled)
rmse = np.sqrt(mean_squared_error(y_test, y_pred))
r2 = r2_score(y_test, y_pred)
print(f"RMSE: {rmse:.4f}")
print(f"R²: {r2:.4f}")
# 6. Coefficients (most important first)
coef_df = pd.DataFrame({
'Feature': housing.feature_names,
'Coefficient': model.coef_
}).sort_values('Coefficient', key=abs, ascending=False)
print(coef_df.to_string(index=False))Quando Usar a Regressão Múltipla
A regressão múltipla é uma boa primeira escolha quando:
- A relação entre cada característica e o alvo é aproximadamente linear
- A interpretabilidade importa — cada coeficiente tem um significado claro
- Você quer uma linha de base rápida antes de tentar modelos complexos
- Você tem amostras suficientes em relação ao número de características (uma regra geral: pelo menos 10–20 observações por característica)
Considere alternativas quando:
| Situação | Alternativa |
|---|---|
| Relações não lineares entre característica e alvo | Regressão Polinomial |
| Muitas características, risco de sobreajuste | Ridge ou Lasso (modelos lineares regularizados) |
| O alvo é uma categoria, não um número | Regressão Logística |
| Interações complexas e não linearidade | Árvores com gradiente boosting ou florestas aleatórias |
Armadilhas Comuns
Ajustar o escalonador em todos os dados antes de dividir. Isso vaza a média e a variância do conjunto de teste para o treinamento. Sempre divida primeiro, depois ajuste o escalonador apenas na parte de treinamento.
Adicionar mais características sempre ajuda. Adicionar características irrelevantes ou redundantes pode reduzir a interpretabilidade, introduzir multicolinearidade e prejudicar a generalização. Use conhecimento de domínio ou uma técnica de seleção de características para escolher as características de forma deliberada.
Confiar nos coeficientes quando as características são correlacionadas. Quando AveRooms e AveBedrms estão ambas no modelo, nenhum dos coeficientes reflete de forma confiável o efeito real dessa variável. Verifique a matriz de correlação antes de interpretar coeficientes individuais.
Ignorar os gráficos de resíduos. Um R² de 0,58 parece razoável no papel, mas padrões nos resíduos podem revelar que o modelo está sistematicamente errado para propriedades de alto valor ou para regiões geográficas específicas.
Extrapolar além do intervalo de treinamento. Um modelo linear treinado em casas com preços entre $50.000 e $500.000 não deve ser usado para prever propriedades de $5.000.000. Verifique se as novas entradas estão dentro do intervalo visto durante o treinamento.
Próximos Passos
- Regressão Linear — a base: regressão simples (uma característica) e o método MQO explicado em detalhes
- Regressão Polinomial — estenda o modelo linear para capturar curvas adicionando termos de características polinomiais
- Escalonamento de Características — aprofundamento em StandardScaler, MinMaxScaler e RobustScaler
- Divisão Treino/Teste — por que a divisão adequada é crítica e como fazê-la sem vazar dados
- Validação Cruzada — uma alternativa mais robusta a uma única divisão treino/teste