Regressione Lineare
Scopri come funziona la regressione lineare, la matematica alla base e come implementarla in Python con scikit-learn, semplice e multipla.
La regressione lineare è uno degli algoritmi più fondamentali nel machine learning. Modella la relazione tra una variabile dipendente (ciò che si vuole prevedere) e una o più variabili indipendenti (gli input) adattando una linea retta — o un iperpiano — ai dati.
Questa pagina copre:
- Come funzionano matematicamente la regressione lineare semplice e quella multipla
- Il metodo dei minimi quadrati ordinari (OLS) per adattare una retta
- Le assunzioni fondamentali da verificare prima di fidarsi del modello
- Una guida completa con scikit-learn: caricare i dati, addestrare, valutare e interpretare i risultati
- Come leggere i coefficienti del modello e individuare le insidie più comuni
Come Funziona la Regressione Lineare
L'Equazione
La regressione lineare semplice (una sola variabile di input) adatta questa retta:
y = β₀ + β₁x + εy— la variabile dipendente (target)x— la variabile indipendente (feature)β₀— l'intercetta (valore di y quando x = 0)β₁— la pendenza (variazione di y per un aumento unitario di x)ε— il termine di errore (rumore che il modello non riesce a spiegare)
La regressione lineare multipla estende questo concetto a n feature:
y = β₀ + β₁x₁ + β₂x₂ + ... + βₙxₙ + εOgni coefficiente βᵢ indica di quanto cambia y quando xᵢ aumenta di un'unità, mantenendo costanti tutte le altre feature.
Minimi Quadrati Ordinari (OLS)
Il modello apprende i coefficienti minimizzando la somma dei residui al quadrato — la differenza tra ogni valore reale yᵢ e la previsione del modello ŷᵢ:
SSR = Σ(yᵢ - ŷᵢ)²L'elevamento al quadrato dei residui penalizza gli errori grandi più di quelli piccoli e garantisce che gli errori positivi e negativi non si annullino a vicenda. Questo criterio ha una soluzione in forma chiusa esatta, motivo per cui la regressione lineare si addestra quasi istantaneamente anche su dataset di grandi dimensioni.
Assunzioni Fondamentali
La regressione lineare produce previsioni affidabili solo quando valgono queste condizioni:
| Assunzione | Cosa verificare |
|---|---|
| Linearità | La relazione tra le feature e il target è approssimativamente lineare |
| Indipendenza | Le osservazioni sono indipendenti tra loro |
| Omoschedasticità | La varianza dei residui è circa costante su tutte le previsioni |
| Normalità dei residui | I residui sono distribuiti approssimativamente in modo normale |
| Assenza di multicollinearità | Le variabili indipendenti non sono altamente correlate tra loro |
Quando queste assunzioni vengono violate, le stime dei coefficienti possono essere distorte oppure il modello può avere prestazioni scarse su dati nuovi.
Esempio di Regressione Lineare Semplice
Prima di passare a più feature, vediamo come l'algoritmo adatta una retta a una singola feature. Questo rende la geometria facile da visualizzare.
import numpy as np
import matplotlib
matplotlib.use('Agg') # non-interactive backend for scripts
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
# Simulate: house size (sq ft) vs price ($1000s)
rng = np.random.default_rng(42)
X_simple = rng.uniform(500, 3000, 50).reshape(-1, 1)
y_simple = 50 + 0.1 * X_simple.ravel() + rng.normal(0, 15, 50)
model = LinearRegression()
model.fit(X_simple, y_simple)
print(f"Intercept (β₀): {model.intercept_:.2f}")
print(f"Slope (β₁): {model.coef_[0]:.4f}")
print(f"Interpretation: each extra sq ft adds ${model.coef_[0]*1000:.0f} to the predicted price")Output atteso:
Intercept (β₀): 46.17
Slope (β₁): 0.1007
Interpretation: each extra sq ft adds $101 to the predicted priceI valori di intercetta e pendenza vengono recuperati automaticamente dall'OLS — non è necessario eseguire alcun calcolo algebrico manualmente.
Regressione Lineare Multipla con scikit-learn
I dataset reali hanno molte feature. Questa sezione illustra una pipeline completa sul dataset California Housing, che registra statistiche abitative a livello di blocco censimento per la California nel 1990.
Passo 1: Importare le Librerie
import pandas as pd
import numpy as np
from sklearn.datasets import fetch_california_housing
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error, r2_scorePasso 2: Caricare ed Esplorare il Dataset
california = fetch_california_housing()
df = pd.DataFrame(california.data, columns=california.feature_names)
df['MedHouseVal'] = california.target # median house value in $100,000s
print(df.shape) # (20640, 9)
print(df.head())
print(df.describe())Il dataset ha 20.640 righe e 8 feature di input:
| Feature | Descrizione |
|---|---|
MedInc | Reddito mediano nel blocco (in decine di migliaia di dollari) |
HouseAge | Età mediana delle abitazioni nel blocco |
AveRooms | Numero medio di stanze per nucleo familiare |
AveBedrms | Numero medio di camere da letto per nucleo familiare |
Population | Popolazione del blocco |
AveOccup | Occupazione media per nucleo familiare |
Latitude | Latitudine del blocco |
Longitude | Longitudine del blocco |
Il target MedHouseVal è il valore mediano delle abitazioni in unità da $100.000.
Passo 3: Scegliere le Feature e Dividere i Dati
Per una dimostrazione semplice, utilizziamo tutte e 8 le feature. Vedi Train/Test Split per una spiegazione dettagliata del motivo per cui si dividono i dati.
X = df[california.feature_names] # all 8 features
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)}") # 4128Il parametro random_state=42 garantisce suddivisioni riproducibili ogni volta che si esegue lo script.
Passo 4: Addestrare il Modello
model = LinearRegression()
model.fit(X_train, y_train)È tutto ciò che occorre. Il metodo fit() risolve il problema OLS analiticamente usando l'algebra matriciale — non è previsto alcun gradient descent iterativo per impostazione predefinita.
Passo 5: Ispezionare i Coefficienti Appresi
Capire ciò che il modello ha appreso è importante quanto la sua accuratezza:
coef_df = pd.DataFrame({
'Feature': california.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 tipico:
Feature Coefficient
AveBedrms 0.7831
MedInc 0.4487
Longitude -0.4337
Latitude -0.4198
AveRooms -0.1233
HouseAge 0.0097
AveOccup -0.0035
Population -0.0000
Intercept: -37.0233Lettura dei coefficienti:
AveBedrms = 0.783: un aumento unitario nel numero medio di camere da letto prevede un aumento di $78.300 nel valore dell'abitazione — ma questo è intrecciato conAveRooms(sono correlati). Quando feature correlate sono entrambe presenti, i singoli coefficienti possono diventare grandi, instabili o addirittura controintuitivi. Questo è il fenomeno della multicollinearità.MedInc = 0.449: un aumento unitario del reddito mediano (circa $10.000) prevede un aumento di $44.900 nel valore dell'abitazione, a parità di tutte le altre condizioni.Longitude = -0.434eLatitude = -0.420: controlli puramente geografici; il modello li utilizza per catturare gli effetti della posizione anche se non riesce a modellare bene la geografia non lineare.
Passo 6: Valutare il Modello
y_pred = model.predict(X_test)
mse = mean_squared_error(y_test, y_pred)
rmse = np.sqrt(mse)
r2 = r2_score(y_test, y_pred)
print(f"RMSE: {rmse:.4f} (in $100,000s, so ±${rmse*100_000:,.0f})")
print(f"R²: {r2:.4f}")Output atteso:
RMSE: 0.7456 (in $100,000s, so ±$74,560)
R²: 0.5758Interpretazione delle metriche:
- RMSE (Root Mean Squared Error) — l'errore medio di previsione nelle stesse unità del target. Valori più bassi sono migliori.
- R² (coefficiente di determinazione) — la proporzione di varianza in
yspiegata dal modello. Un R² di 0,58 significa che il modello spiega circa il 58% della varianza nei prezzi delle abitazioni. Valori vicini a 1,0 sono migliori; valori vicini a 0 indicano che il modello è a malapena migliore della previsione della media.
Un R² di ~0,58 è tipico per questo dataset con la regressione lineare. La relazione tra i prezzi delle abitazioni e queste feature è in parte non lineare, motivo per cui metodi come la regressione polinomiale o il gradient boosting ottengono spesso punteggi più alti.
Passo 7: Visualizzare i Valori Previsti vs Effettivi
Il grafico diagnostico più chiaro per un modello di regressione è previsto vs effettivo — funziona indipendentemente dal numero di feature che si hanno:
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
plt.figure(figsize=(7, 5))
plt.scatter(y_test, y_pred, alpha=0.3, s=10, color='steelblue')
plt.plot([y_test.min(), y_test.max()],
[y_test.min(), y_test.max()],
'r--', linewidth=1.5, label='Perfect prediction')
plt.xlabel('Actual Median House Value ($100,000s)')
plt.ylabel('Predicted Median House Value ($100,000s)')
plt.title('Linear Regression: Predicted vs Actual')
plt.legend()
plt.tight_layout()
plt.savefig('lr_predicted_vs_actual.png', dpi=120)
print("Plot saved.")I punti che cadono sulla linea tratteggiata rossa sono previsioni perfette. La dispersione attorno alla linea mostra l'errore. Una forma a ventaglio (dispersione più ampia per valori più alti) segnala eteroschedasticità — una delle assunzioni fondamentali è violata.
Pipeline Completa (Tutti i Passi Insieme)
import pandas as pd
import numpy as np
from sklearn.datasets import fetch_california_housing
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error, r2_score
# Load data
california = fetch_california_housing()
df = pd.DataFrame(california.data, columns=california.feature_names)
df['MedHouseVal'] = california.target
# Split
X = df[california.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)
# Train
model = LinearRegression()
model.fit(X_train, y_train)
# Evaluate
y_pred = model.predict(X_test)
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}")Quando Usare la Regressione Lineare
La regressione lineare è una buona prima scelta quando:
- La relazione tra input e output è approssimativamente lineare
- L'interpretabilità è importante — è necessario spiegare le previsioni agli stakeholder
- Il dataset è di dimensioni piccole o medie e la velocità di addestramento è importante
- Si desidera una baseline rapida prima di provare modelli più complessi
Considera delle alternative quando:
- Le feature e il target hanno relazioni fortemente non lineari → prova la regressione polinomiale o gli alberi decisionali
- Hai molte feature che potrebbero essere irrilevanti → le varianti regolarizzate (Ridge, Lasso) prevengono l'overfitting riducendo i coefficienti
- Il target è una categoria, non un numero → usa invece la regressione logistica
Insidie Comuni
Dimenticare di scalare le feature. I coefficienti della regressione lineare riflettono le unità di ciascuna feature. Se una feature è espressa in migliaia e un'altra in frazioni, le dimensioni dei coefficienti grezzi non sono comparabili. Usa StandardScaler prima di confrontare le importanze delle feature. Vedi Feature Scaling per i dettagli.
Multicollinearità. Feature altamente correlate rendono i singoli coefficienti inaffidabili — possono persino cambiare segno. Controlla la matrice di correlazione con df.corr() e rimuovi o combina le feature correlate.
Estrapolazione. Un modello lineare addestrato su dati in un certo intervallo può fornire previsioni completamente errate al di fuori di quell'intervallo. Verifica sempre che i nuovi input ricadano nella distribuzione di addestramento.
Ignorare i grafici dei residui. Traccia sempre i residui dopo l'adattamento. I pattern nei residui (curve, ventagli, cluster di outlier) indicano che le assunzioni del modello sono violate e le previsioni non dovrebbero essere considerate affidabili senza ulteriori indagini.
Passi Successivi
Una volta ottenuta una baseline di regressione lineare funzionante, esplora questi argomenti correlati:
- Multiple Regression — approfondimento sull'uso di più feature e sull'interpretazione di ciascun coefficiente
- Polynomial Regression — adatta curve invece di rette aggiungendo termini di feature polinomiali
- Train/Test Split — comprendi perché e come valutare correttamente le prestazioni del modello
- Feature Scaling — standardizza gli input affinché i coefficienti e i solver basati su gradiente si comportino correttamente
- Logistic Regression — prevedi categorie (sì/no, spam/non-spam) invece di valori continui