W3docs

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 de y lorsque chaque variable est égale à zéro
  • β₁ … βₙ — les coefficients : la variation de y pour une augmentation d'une unité de chaque xᵢ, en maintenant toutes les autres variables constantes
  • ε — le terme d'erreur : la partie de y que 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 :

VariableDescription
MedIncRevenu médian du bloc (en dizaines de milliers de dollars)
HouseAgeÂge médian des logements du bloc
AveRoomsNombre moyen de pièces par ménage
AveBedrmsNombre moyen de chambres par ménage
PopulationPopulation du bloc
AveOccupOccupation moyenne des ménages
LatitudeLatitude du bloc
LongitudeLongitude 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 transformation

La 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.5758

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

Lecture 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.897 et Longitude = -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.339 vs AveRooms = -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é : AveRooms et AveBedrms sont 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,895

Le 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 variablesCorrélationPréoccupation
AveRooms / AveBedrms0,85Élevée — les coefficients se compensent mutuellement
Latitude / Longitude-0,93Très élevée — co-mouvement géographique
MedInc / MedHouseVal (cible)0,69Bon 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 :

  1. Supprimer l'une des variables corrélées. Si AveRooms et AveBedrms sont toutes deux dans le modèle, essayez de supprimer AveBedrms et vérifiez si les performances prédictives du modèle changent significativement.
  2. Les combiner. Créer une variable dérivée (par ex., rooms_per_bedroom = AveRooms / AveBedrms) qui capture la relation sans redondance.
  3. 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.7457

La 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 :

SituationAlternative
Relations non linéaires entre variables et cibleRégression Polynomiale
Nombreuses variables, risque de surapprentissageRidge ou Lasso (modèles linéaires régularisés)
La cible est une catégorie, pas un nombreRé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
Was this page helpful?