W3docs

Regressione Multipla

Scopri come funziona la regressione lineare multipla, interpreta i coefficienti, gestisci la multicollinearità e costruisci un modello completo in Python.

La regressione lineare multipla estende la regressione lineare semplice utilizzando due o più variabili indipendenti per prevedere un target continuo. Invece di tracciare una retta in due dimensioni, il modello adatta un iperpiano attraverso tante dimensioni quante sono le feature. Comprendere come i coefficienti interagiscono — e quando possono trarre in inganno — è la competenza fondamentale che questa pagina insegna.

Questa pagina tratta:

  • L'equazione della regressione multipla e il significato di ciascun coefficiente
  • Come costruire una pipeline completa con scikit-learn: caricamento, preprocessing, addestramento, valutazione
  • Perché il feature scaling è importante e come eseguirlo correttamente
  • Come interpretare e confrontare coefficienti scalati e non scalati
  • La diagnosi della multicollinearità — l'insidia più comune nella regressione multipla
  • L'analisi dei residui per verificare le assunzioni del modello
  • Quando scegliere la regressione multipla e cosa provare quando non è sufficiente

L'Equazione della Regressione Multipla

La regressione lineare multipla modella il target y come combinazione lineare di n feature di input:

y = β₀ + β₁x₁ + β₂x₂ + ... + βₙxₙ + ε
  • β₀ — l'intercetta: il valore previsto di y quando ogni feature è uguale a zero
  • β₁ … βₙ — i coefficienti: di quanto cambia y per un aumento di un'unità in ciascuna xᵢ, mantenendo costanti tutte le altre feature
  • ε — il termine di errore: la parte di y che il modello non riesce a spiegare

L'algoritmo trova i coefficienti minimizzando la somma dei residui al quadrato (ordinary least squares):

SSR = Σ(yᵢ - ŷᵢ)²

Questo ha una soluzione analitica esatta in forma chiusa, quindi LinearRegression di scikit-learn non necessita di gradient descent iterativo — l'addestramento è quasi istantaneo anche su dataset con centinaia di migliaia di righe.

Differenza dalla Regressione Lineare Semplice

La regressione lineare semplice utilizza una sola feature. La regressione multipla aggiunge più feature in modo che ciascun coefficiente catturi l'effetto parziale di quella feature — il suo impatto sul target mentre le feature rimanenti sono tenute costanti. Questo è più potente ma introduce nuovi rischi, in particolare la multicollinearità (vedi Diagnosi della Multicollinearità).

Il Dataset

Gli esempi di seguito utilizzano il dataset California Housing integrato in scikit-learn. Registra statistiche abitative a livello di blocco censimento per la California nel 1990 e contiene 20.640 campioni distribuiti su 8 feature.

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())

Le 8 feature di input sono:

FeatureDescrizione
MedIncReddito mediano del blocco (in decine di migliaia di dollari)
HouseAgeEtà mediana delle abitazioni nel blocco
AveRoomsNumero medio di stanze per nucleo familiare
AveBedrmsNumero medio di camere da letto per nucleo familiare
PopulationPopolazione del blocco
AveOccupOccupazione media del nucleo familiare
LatitudeLatitudine del blocco
LongitudeLongitudine del blocco

Il target MedHouseVal è il valore mediano delle abitazioni in unità di $100.000, quindi un valore di 2.0 rappresenta $200.000.

Costruire il Modello Passo per Passo

Passo 1 — Suddividere i Dati

Suddividi sempre i dati prima di qualsiasi preprocessing. Adattare uno scaler sull'intero dataset farebbe trapelare le statistiche del test set nell'addestramento, fornendo una valutazione eccessivamente ottimistica. Vedi Train/Test Split per una spiegazione 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)}")   # 4128

Passo 2 — Scalare le Feature

I coefficienti della regressione multipla riflettono le unità di ciascuna feature. MedInc è misurata in decine di migliaia di dollari; Population è un conteggio grezzo che può raggiungere 35.000. Senza scaling, il coefficiente di Population sarà piccolo non perché la popolazione sia irrilevante, ma perché la sua unità è piccola.

StandardScaler trasforma ogni feature in modo che abbia media zero e deviazione standard unitaria, rendendo le magnitudini dei coefficienti direttamente confrontabili. Vedi Feature Scaling per i dettagli sugli scaler disponibili.

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 transformation

La regola fondamentale: chiama fit_transform sui dati di addestramento e transform (senza fit) sui dati di test. Eseguire il fit sui dati di test contaminerebbe la valutazione.

Passo 3 — Addestrare il Modello

from sklearn.linear_model import LinearRegression

model = LinearRegression()
model.fit(X_train_scaled, y_train)

LinearRegression.fit() risolve il problema OLS analiticamente. Non ci sono iperparametri da ottimizzare nella regressione multipla standard — quello che si sceglie è quali feature includere.

Passo 4 — Valutare il Modello

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}")

Output atteso:

Mean Squared Error:      0.5559
Root Mean Squared Error: 0.7456  (±$74,558)
R-squared:               0.5758

Cosa significano le metriche:

  • MSE (Mean Squared Error) — media delle differenze al quadrato tra previsioni e valori reali. Il quadrato penalizza gli errori grandi più di quelli piccoli. Le unità sono il quadrato del target ($100.000²), quindi è più difficile da interpretare direttamente.
  • RMSE (Root Mean Squared Error) — la radice quadrata dell'MSE, espressa nelle stesse unità del target. Un RMSE di 0,75 significa che le previsioni del modello si discostano in media di circa $75.000.
  • R² (coefficiente di determinazione) — la frazione della varianza del target spiegata dal modello. Un R² di 0,58 significa che il modello cattura il 58% della variazione dei prezzi delle abitazioni. I valori vanno da 0 (non meglio della previsione della media) a 1 (previsioni perfette). Un R² negativo è possibile se il modello è peggiore della media — è un segnale forte che qualcosa non va.

Un R² di ~0,58 è tipico per questo dataset con la regressione lineare standard. La relazione tra i prezzi delle abitazioni e queste feature è in parte non lineare e coinvolge raggruppamenti geografici che un iperpiano non riesce a catturare bene. Algoritmi come i gradient-boosted tree raggiungono regolarmente 0,80+ su questo dataset.

Passo 5 — Esaminare i Coefficienti

Dopo lo scaling, le magnitudini dei coefficienti sono direttamente confrontabili — mostrano quali feature influenzano maggiormente la previsione:

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}")

Output atteso:

   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.0719

Lettura dei coefficienti dopo la standardizzazione:

  • MedInc = 0.854 — il predittore singolarmente più forte. Un aumento di una deviazione standard nel reddito mediano prevede un aumento di $85.400 nel valore dell'abitazione, mantenendo tutto il resto costante.
  • Latitude = -0.897 e Longitude = -0.869 — il modello ha appreso che i blocchi censimento più a nord e più a est tendono ad essere più economici. Tuttavia, queste due feature geografiche sono altamente correlate (r = -0,93), il che può rendere instabili i loro coefficienti individuali (vedi Diagnosi della Multicollinearità).
  • AveBedrms = +0.339 vs AveRooms = -0.294 — hanno segni opposti anche se più stanze e più camere da letto in genere significano case più grandi e costose. Questo è un classico segnale di multicollinearità: AveRooms e AveBedrms sono correlate (r = 0,85), quindi i loro coefficienti si compensano a vicenda. Non interpretarli in isolamento.
  • Population = -0.002 — molto vicino a zero dopo lo scaling. La popolazione del blocco ha un potere predittivo minimo una volta tenute in conto le altre feature.

L'intercetta (2,07) è il MedHouseVal previsto quando ogni feature scalata è zero — ovvero quando tutte le feature sono alla loro media del training set. Corrisponde alla media dei target di addestramento e non ha un significato aziendale diretto al di là di questo.

Passo 6 — Fare Previsioni su Nuovi Dati

# 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}")

Output atteso:

Predicted median house value: $410,895

Lo scaler deve essere lo stesso scaler adattato sui dati di addestramento. Non riadattare mai lo scaler sui nuovi dati — ciò sposterebbe gli input rispetto a ciò che il modello ha appreso.

Diagnosi della Multicollinearità

La multicollinearità si verifica quando due o più variabili indipendenti sono altamente correlate tra loro. Non impedisce al modello di fare previsioni accurate, ma rende i coefficienti individuali inaffidabili e difficili da interpretare. I coefficienti possono diventare grandi, cambiare segno o diventare statisticamente non significativi anche per feature genuinamente importanti.

Verifica con una Matrice di Correlazione

import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt

corr = df[housing.feature_names].corr()
print(corr.round(2))

Coppie chiave da osservare:

Coppia di featureCorrelazioneProblema
AveRooms / AveBedrms0,85Alta — i coefficienti si compensano a vicenda
Latitude / Longitude-0,93Molto alta — co-movimento geografico
MedInc / MedHouseVal (target)0,69Buon predittore, non è un problema di collinearità

Una correlazione superiore a 0,80 tra due feature è un segnale d'allarme. Quando la si riscontra, considera:

  1. Eliminare una delle feature correlate. Se sia AveRooms che AveBedrms sono nel modello, prova a rimuovere AveBedrms e verifica se le prestazioni predittive del modello cambiano molto.
  2. Combinarle. Crea una feature derivata (es. rooms_per_bedroom = AveRooms / AveBedrms) che cattura la relazione senza ridondanza.
  3. Usare un modello regolarizzato. La regressione Ridge aggiunge una penalità L2 che riduce i coefficienti correlati verso i loro valori medi, stabilizzandoli. Lasso (L1) può azzerare completamente le feature ridondanti.

Analisi dei Residui

Un residuo è la differenza tra un valore reale e la previsione del modello: residual = y_actual - y_predicted. Tracciare i residui rivela se le assunzioni del modello sono verificate.

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}")

Output atteso:

Mean of residuals: 0.0035
Std of residuals:  0.7457

La media è vicina a zero — un segnale che il modello è non distorto in media. Ma la deviazione standard di 0,75 (±$75.000) mostra una dispersione sostanziale.

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")

Cosa cercare:

  • Previsti vs Reali — idealmente, i punti cadono lungo la diagonale. Una deviazione sistematica dalla diagonale (una curva, o un appiattimento ai valori alti) significa che l'assunzione lineare è errata per parte dell'intervallo.
  • Residui vs Previsti — idealmente, i residui si disperdono casualmente attorno allo zero a tutti i livelli di previsione. Una forma a imbuto (dispersione più ampia a previsioni più alte) segnala eteroschedasticità — l'errore del modello non è costante, il che può rendere inaffidabili le stime degli intervalli.
  • Cluster — gruppi distinti nel grafico dei residui possono rivelare che il dataset contiene sotto-popolazioni (es. urbano vs rurale) che richiedono modelli separati o feature aggiuntive.

Pipeline Completa

Ecco tutto quanto sopra come script eseguibile in una sola volta:

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 Usare la Regressione Multipla

La regressione multipla è una scelta iniziale valida quando:

  • La relazione tra ciascuna feature e il target è approssimativamente lineare
  • L'interpretabilità è importante — ogni coefficiente ha un significato chiaro
  • Si vuole una baseline rapida prima di provare modelli complessi
  • Si hanno abbastanza campioni rispetto al numero di feature (regola approssimativa: almeno 10–20 osservazioni per feature)

Considera alternative quando:

SituazioneAlternativa
Relazioni non lineari tra feature e targetRegressione Polinomiale
Molte feature, rischio di overfittingRidge o Lasso (modelli lineari regolarizzati)
Il target è una categoria, non un numeroRegressione Logistica
Interazioni complesse e non linearitàGradient-boosted tree o random forest

Errori Comuni

Adattare lo scaler su tutti i dati prima della suddivisione. Questo fa trapelare la media e la varianza del test set nell'addestramento. Suddividi sempre prima, poi adatta lo scaler solo sulla porzione di addestramento.

Aggiungere più feature aiuta sempre. Aggiungere feature irrilevanti o ridondanti può ridurre l'interpretabilità, introdurre multicollinearità e peggiorare la generalizzazione. Usa la conoscenza del dominio o una tecnica di selezione delle feature per scegliere le feature in modo deliberato.

Fidarsi dei coefficienti quando le feature sono correlate. Quando sia AveRooms che AveBedrms sono nel modello, nessuno dei due coefficienti riflette in modo affidabile il vero effetto di quella variabile. Controlla la matrice di correlazione prima di interpretare i coefficienti individuali.

Ignorare i grafici dei residui. Un R² di 0,58 sembra ragionevole sulla carta, ma i pattern dei residui possono rivelare che il modello è sistematicamente errato per le proprietà di alto valore o per specifiche regioni geografiche.

Estrapolare oltre l'intervallo di addestramento. Un modello lineare addestrato su abitazioni con prezzi tra $50.000 e $500.000 non dovrebbe essere usato per prevedere proprietà da $5.000.000. Verifica che i nuovi input rientrino nell'intervallo osservato durante l'addestramento.

Prossimi Passi

  • Regressione Lineare — le fondamenta: la regressione semplice (con una feature) e il metodo OLS spiegato per intero
  • Regressione Polinomiale — estendi il modello lineare per catturare curve aggiungendo termini di feature polinomiali
  • Feature Scaling — approfondimento su StandardScaler, MinMaxScaler e RobustScaler
  • Train/Test Split — perché la suddivisione corretta è fondamentale e come eseguirla senza far trapelare i dati
  • Cross-Validation — un'alternativa più robusta a una singola suddivisione train/test
Was this page helpful?