Régression Multiple
Apprenez la régression linéaire multiple, interprétez les coefficients, gérez la multicolinéarité et construisez un modèle Python avec scikit-learn.
La régression linéaire multiple étend la régression linéaire simple en utilisant deux variables indépendantes ou plus pour prédire une cible continue. Au lieu de tracer une droite dans deux dimensions, le modèle ajuste un hyperplan dans autant de dimensions qu'il y a de variables. Comprendre comment les coefficients interagissent — et quand ils peuvent être trompeurs — est la compétence fondamentale enseignée sur cette page.
Cette page aborde :
- L'équation de régression multiple et la signification de chaque coefficient
- Comment construire un pipeline scikit-learn complet : chargement, prétraitement, entraînement, évaluation
- Pourquoi la mise à l'échelle des variables est importante et comment la réaliser correctement
- Comment interpréter et comparer les coefficients mis à l'échelle et non mis à l'échelle
- Le diagnostic de la multicolinéarité — le piège le plus courant en régression multiple
- L'analyse des résidus pour vérifier les hypothèses du modèle
- Quand choisir la régression multiple et quelles alternatives envisager en cas de limitation
L'équation de régression multiple
La régression linéaire multiple modélise la cible y comme une combinaison linéaire de n variables d'entrée :
y = β₀ + β₁x₁ + β₂x₂ + ... + βₙxₙ + εβ₀— l'ordonnée à l'origine : la valeur prédite deylorsque chaque variable est égale à zéroβ₁ … βₙ— les coefficients : la variation deypour une augmentation d'une unité de chaquexᵢ, en maintenant toutes les autres variables constantesε— le terme d'erreur : la partie deyque le modèle ne peut pas expliquer
L'algorithme trouve les coefficients en minimisant la somme des carrés des résidus (moindres carrés ordinaires) :
SSR = Σ(yᵢ - ŷᵢ)²Cela possède une solution analytique exacte, donc LinearRegression de scikit-learn n'a pas besoin d'une descente de gradient itérative — l'entraînement est quasi instantané même sur des jeux de données comportant des centaines de milliers de lignes.
Différence avec la régression linéaire simple
La régression linéaire simple utilise une seule variable. La régression multiple ajoute davantage de variables afin que chaque coefficient capture l'effet partiel de cette variable — son impact sur la cible tandis que les autres variables restent constantes. C'est plus puissant, mais cela introduit de nouveaux risques, notamment la multicolinéarité (voir Diagnostic de la multicolinéarité).
Le jeu de données
Les exemples ci-dessous utilisent le jeu de données California Housing intégré à scikit-learn. Il enregistre des statistiques de logement au niveau des blocs de recensement pour la Californie en 1990 et contient 20 640 échantillons répartis sur 8 variables.
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())Les 8 variables d'entrée sont :
| Variable | Description |
|---|---|
MedInc | Revenu médian du bloc (en dizaines de milliers de dollars) |
HouseAge | Âge médian des logements du bloc |
AveRooms | Nombre moyen de pièces par ménage |
AveBedrms | Nombre moyen de chambres par ménage |
Population | Population du bloc |
AveOccup | Occupation moyenne des ménages |
Latitude | Latitude du bloc |
Longitude | Longitude du bloc |
La cible MedHouseVal est la valeur médiane des logements en unités de 100 000 $, donc une valeur de 2.0 représente 200 000 $.
Construction du modèle étape par étape
Étape 1 — Diviser les données
Divisez toujours les données avant tout prétraitement. Ajuster un scaler sur l'ensemble du jeu de données ferait fuiter les statistiques du jeu de test dans l'entraînement, vous donnant une évaluation trop optimiste. Voir Train/Test Split pour une explication complète.
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Étape 2 — Mettre les variables à l'échelle
Les coefficients de régression multiple reflètent les unités de chaque variable. MedInc est mesuré en dizaines de milliers de dollars ; Population est un comptage brut qui peut atteindre 35 000. Sans mise à l'échelle, le coefficient de Population sera minuscule non pas parce que la population est sans importance, mais parce que son unité est petite.
StandardScaler transforme chaque variable pour qu'elle ait une moyenne nulle et un écart-type unitaire, rendant les magnitudes des coefficients directement comparables. Voir Feature Scaling pour plus de détails sur les scalers disponibles.
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 transformationLa règle essentielle : appelez fit_transform sur les données d'entraînement et transform (sans ajustement) sur les données de test. Ajuster sur les données de test contaminerait l'évaluation.
Étape 3 — Entraîner le modèle
from sklearn.linear_model import LinearRegression
model = LinearRegression()
model.fit(X_train_scaled, y_train)LinearRegression.fit() résout le problème des moindres carrés de manière analytique. Il n'y a pas d'hyperparamètres à régler pour une régression multiple classique — ce que vous choisissez, c'est quelles variables inclure.
Étape 4 — Évaluer le modèle
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}")Sortie attendue :
Mean Squared Error: 0.5559
Root Mean Squared Error: 0.7456 (±$74,558)
R-squared: 0.5758Ce que signifient les métriques :
- MSE (Mean Squared Error) — moyenne des différences au carré entre les prédictions et les valeurs réelles. Le fait de mettre au carré pénalise davantage les grandes erreurs que les petites. Les unités sont le carré de la cible (100 000 $²), ce qui rend l'interprétation directe plus difficile.
- RMSE (Root Mean Squared Error) — la racine carrée du MSE, exprimée dans les mêmes unités que la cible. Un RMSE de 0,75 signifie que les prédictions du modèle s'écartent d'environ 75 000 $ en moyenne.
- R² (coefficient de détermination) — la fraction de variance de la cible que le modèle explique. Un R² de 0,58 signifie que le modèle capture 58 % de la variation des prix des logements. Les valeurs vont de 0 (pas mieux que de prédire la moyenne) à 1 (prédictions parfaites). Un R² négatif est possible si le modèle est moins performant que la moyenne — c'est un signe fort que quelque chose ne va pas.
Un R² d'environ 0,58 est typique pour ce jeu de données avec une régression linéaire classique. La relation entre les prix des logements et ces variables est partiellement non linéaire et implique une concentration géographique qu'un hyperplan ne peut pas bien capturer. Des algorithmes comme les arbres à gradient boosté atteignent régulièrement 0,80+ sur ce jeu de données.
Étape 5 — Inspecter les coefficients
Après la mise à l'échelle, les magnitudes des coefficients sont directement comparables — elles indiquent quelles variables influencent le plus fortement la prédiction :
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}")Sortie attendue :
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.0719Lecture des coefficients après la standardisation :
MedInc = 0.854— le prédicteur le plus fort. Une augmentation d'un écart-type du revenu médian prédit une augmentation de 85 400 $ de la valeur du logement, en maintenant tout le reste constant.Latitude = -0.897etLongitude = -0.869— le modèle a appris que les blocs de recensement plus au nord et plus à l'est tendent à être moins chers. Cependant, ces deux variables géographiques sont fortement corrélées (r = -0,93), ce qui peut rendre leurs coefficients individuels instables (voir Diagnostic de la multicolinéarité).AveBedrms = +0.339vsAveRooms = -0.294— ces variables ont des signes opposés même si plus de pièces et plus de chambres signifient généralement des logements plus grands et plus chers. C'est un signe classique de multicolinéarité :AveRoomsetAveBedrmssont corrélées (r = 0,85), donc leurs coefficients se compensent mutuellement. Ne les interprétez pas isolément.Population = -0.002— très proche de zéro après la mise à l'échelle. La population du bloc a un pouvoir prédictif minimal une fois les autres variables prises en compte.
L'ordonnée à l'origine (2,07) est la MedHouseVal prédite lorsque chaque variable mise à l'échelle est nulle — c'est-à-dire lorsque toutes les variables sont à leur moyenne sur le jeu d'entraînement. Elle est égale à la moyenne des cibles d'entraînement et n'a pas de signification métier directe au-delà de cela.
Étape 6 — Faire des prédictions sur de nouvelles données
# 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}")Sortie attendue :
Predicted median house value: $410,895Le scaler doit être le même scaler ajusté sur les données d'entraînement. Ne réajustez jamais le scaler sur les nouvelles données — cela décalerait les entrées par rapport à ce que le modèle a appris.
Diagnostic de la multicolinéarité
La multicolinéarité survient lorsque deux variables indépendantes ou plus sont fortement corrélées entre elles. Cela n'empêche pas le modèle de faire des prédictions précises, mais rend les coefficients individuels peu fiables et difficiles à interpréter. Les coefficients peuvent devenir grands, changer de signe, ou devenir statistiquement insignifiants même pour des variables genuinement importantes.
Vérification avec une matrice de corrélation
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
corr = df[housing.feature_names].corr()
print(corr.round(2))Paires clés à observer :
| Paire de variables | Corrélation | Préoccupation |
|---|---|---|
AveRooms / AveBedrms | 0,85 | Élevée — les coefficients se compensent mutuellement |
Latitude / Longitude | -0,93 | Très élevée — co-mouvement géographique |
MedInc / MedHouseVal (cible) | 0,69 | Bon prédicteur, pas un problème de colinéarité |
Une corrélation supérieure à 0,80 entre deux variables est un signal d'alarme. Lorsque vous la détectez, envisagez :
- Supprimer l'une des variables corrélées. Si
AveRoomsetAveBedrmssont toutes deux dans le modèle, essayez de supprimerAveBedrmset vérifiez si les performances prédictives du modèle changent significativement. - Les combiner. Créer une variable dérivée (par ex.,
rooms_per_bedroom = AveRooms / AveBedrms) qui capture la relation sans redondance. - Utiliser un modèle régularisé. La régression Ridge ajoute une pénalité L2 qui réduit les coefficients corrélés les uns vers les autres, les stabilisant. Lasso (L1) peut mettre à zéro les variables redondantes entièrement.
Analyse des résidus
Un résidu est la différence entre une valeur réelle et la prédiction du modèle : residual = y_actual - y_predicted. Tracer les résidus révèle si les hypothèses du modèle sont respectées.
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}")Sortie attendue :
Mean of residuals: 0.0035
Std of residuals: 0.7457La moyenne est proche de zéro — signe que le modèle est non biaisé en moyenne. Mais l'écart-type de 0,75 (±75 000 $) montre une dispersion substantielle.
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")Ce qu'il faut observer :
- Prédictions vs Valeurs réelles — idéalement, les points s'alignent sur la diagonale. Une déviation systématique de la diagonale (une courbe, ou un aplatissement aux valeurs élevées) signifie que l'hypothèse linéaire est erronée pour une partie de la plage.
- Résidus vs Prédictions — idéalement, les résidus se dispersent aléatoirement autour de zéro à tous les niveaux de prédiction. Une forme en entonnoir (dispersion plus large aux prédictions plus élevées) signale une hétéroscédasticité — l'erreur du modèle n'est pas constante, ce qui peut rendre les estimations d'intervalle peu fiables.
- Groupes — des groupes distincts dans le graphique des résidus peuvent révéler que le jeu de données contient des sous-populations (par ex., urbaines vs rurales) qui nécessitent des modèles séparés ou des variables supplémentaires.
Pipeline complet
Voici tout ce qui précède sous la forme d'un script exécutable unique :
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))Quand utiliser la régression multiple
La régression multiple est un premier choix solide lorsque :
- La relation entre chaque variable et la cible est approximativement linéaire
- L'interprétabilité est importante — chaque coefficient a une signification claire
- Vous souhaitez une ligne de base rapide avant d'essayer des modèles complexes
- Vous avez suffisamment d'échantillons par rapport au nombre de variables (règle approximative : au moins 10 à 20 observations par variable)
Envisagez des alternatives lorsque :
| Situation | Alternative |
|---|---|
| Relations non linéaires entre variables et cible | Régression Polynomiale |
| Nombreuses variables, risque de surapprentissage | Ridge ou Lasso (modèles linéaires régularisés) |
| La cible est une catégorie, pas un nombre | Régression Logistique |
| Interactions complexes et non-linéarité | Arbres à gradient boosté ou forêts aléatoires |
Pièges courants
Ajuster le scaler sur toutes les données avant de diviser. Cela fait fuiter la moyenne et la variance du jeu de test dans l'entraînement. Divisez toujours d'abord, puis ajustez le scaler uniquement sur la partie d'entraînement.
Penser qu'ajouter plus de variables aide toujours. Ajouter des variables non pertinentes ou redondantes peut réduire l'interprétabilité, introduire la multicolinéarité et nuire à la généralisation. Utilisez la connaissance du domaine ou une technique de sélection de variables pour choisir les variables délibérément.
Faire confiance aux coefficients lorsque les variables sont corrélées. Quand AveRooms et AveBedrms sont toutes deux dans le modèle, aucun coefficient ne reflète de manière fiable l'effet réel de cette variable. Vérifiez la matrice de corrélation avant d'interpréter les coefficients individuels.
Ignorer les graphiques de résidus. Un R² de 0,58 semble raisonnable sur le papier, mais les patterns des résidus peuvent révéler que le modèle est systématiquement erroné pour les propriétés de grande valeur ou pour des régions géographiques spécifiques.
Extrapoler au-delà de la plage d'entraînement. Un modèle linéaire entraîné sur des logements dont le prix est compris entre 50 000 $ et 500 000 $ ne devrait pas être utilisé pour prédire des propriétés à 5 000 000 $. Vérifiez que les nouvelles entrées se situent dans la plage observée lors de l'entraînement.
Prochaines étapes
- Régression Linéaire — les bases : la régression simple (à une variable) et la méthode des moindres carrés expliquées en détail
- Régression Polynomiale — étendre le modèle linéaire pour capturer des courbes en ajoutant des termes de variables polynomiales
- Feature Scaling — approfondissement de StandardScaler, MinMaxScaler et RobustScaler
- Train/Test Split — pourquoi une division appropriée est cruciale et comment la réaliser sans faire fuiter les données
- Cross-Validation — une alternative plus robuste à un seul découpage entraînement/test