Random Forest (Régression) : Guide Complet — Principes, Exemples et Implémentation Python

Random Forest (Régression) : Guide Complet — Principes, Exemples et Implémentation Python

Random Forest (Régression) : Guide complet — Principes, Exemples et Implémentation Python

Résumé

Le Random Forest (forêt aléatoire) appliqué à la régression est l’une des méthodes d’ensemble les plus populaires en apprentissage supervisé. Contrairement à la version classification qui utilise un vote majoritaire, le Random Forest en régression effectue une moyenne des prédictions de tous les arbres constituant la forêt. Cette approche, introduite par Leo Breiman en 2001, combine la puissance du bagging (Bootstrap Aggregating) avec la sélection aléatoire des variables à chaque split, produisant un modèle robuste, précis et résistant au surapprentissage.

Ce guide complet explore les principes mathématiques, l’intuition, l’implémentation pratique en Python avec scikit-learn et les cas d’usage concrets du random forest régression.

Principe mathématique du Random Forest régression

Construction de la forêt

Le Random Forest régression construit B arbres de décision indépendants, chacun entraîné sur un échantillon bootstrap (tirage avec remise) de taille n issu du jeu d’entraînement original.

Le processus se décompose ainsi :

1. Échantillonnage bootstrap : Pour chaque arbre b (de 1 à B), on tire n observations avec remise depuis le jeu d’entraînement. En moyenne, environ 63,2 % des observations uniques apparaissent dans chaque échantillon bootstrap. Les observations restantes (≈ 36,8 %) forment l’ensemble Out-Of-Bag (OOB), utilisé pour l’évaluation interne.

2. Construction de chaque arbre : À chaque nœud de chaque arbre, au lieu de chercher la meilleure variable parmi l’ensemble des p variables disponibles comme le ferait un arbre classique, on tire aléatoirement un sous-ensemble de m variables (m < p, typiquement m = p/3 pour la régression). Le meilleur split est choisi uniquement parmi ces m variables candidates. Cette restriction aléatoire décorrèle les arbres entre eux, ce qui est essentiel pour que la moyenne des prédictions soit effectivement plus performante qu’un arbre unique.

3. Prédiction par moyenne : Pour une nouvelle observation x, chaque arbre b produit une prédiction f_b(x). La prédiction finale du Random Forest régression est la moyenne arithmétique de toutes les prédictions individuelles :

$$
\hat{f}{RF}(x) = \frac{1}{B}\sum f_b(x)
$$}^{B

Cette simple moyenne est remarquablement efficace pour réduire la variance de la prédiction finale.

Erreur Out-Of-Bag (OOB MSE)

L’erreur OOB est calculée en évaluant chaque observation uniquement sur les arbres qui ne l’ont pas vue pendant l’entraînement (les arbres pour lesquels cette observation était hors de l’échantillon bootstrap). Le Mean Squared Error OOB s’écrit :

$$
\mathrm{MSE}{OOB} = \frac{1}{n}\sum(x_i)\right)^2
$$}^{n}\left(y_i – \hat{f}_{RF}^{OOB

f_RF_OOB(x_i) est la moyenne des prédictions pour x_i produites uniquement par les arbres qui n’ont pas été entraînés avec l’observation i. Cette métrique offre une estimation sans biais de l’erreur de généralisation, sans nécessiter de jeu de validation séparé.

Réduction de variance

Le théorème fondamental derrière le Random Forest est le suivant : si chaque arbre individuel a une variance $\mathrm{Var}(f_b) = \sigma^2$ et que les arbres ont une corrélation $\rho$ entre eux, alors la variance de la moyenne des $B$ arbres est :

$$
\mathrm{Var}(\hat{f}_{RF}) = \rho \sigma^2 + \frac{1 – \rho}{B}\sigma^2
$$

Quand $B$ tend vers l’infini, la variance converge vers $\rho \sigma^2$. La clé est donc de réduire la corrélation $\rho$ entre les arbres, ce que la sélection aléatoire des variables à chaque split permet de faire efficacement.

Intuition : pourquoi la moyenne bat l’arbre unique

Imaginez que vous devez estimer le prix d’un appartement. Vous demandez à un seul agent immobilier : il pourrait se tromper car son estimation dépend de son expérience personnelle, de ses biais cognitifs et des quelques transactions qu’il a en tête.

Maintenant, imaginez que vous demandez à 500 agents immobiliers indépendants, chacun ayant étudié un échantillon légèrement différent du marché local avec des critères légèrement différents. Si vous prenez la moyenne de toutes leurs estimations, le résultat sera presque certainement plus fiable que celui d’un seul expert. C’est exactement l’idée du Random Forest régression.

Chaque arbre de la forêt est un « expert » partiel :

  • Il est entraîné sur un sous-ensemble aléatoire des données (bootstrap), donc il ne voit pas toute l’histoire.
  • À chaque décision de split, il ne considère qu’un sous-ensemble aléatoire des variables, donc il ne repose pas toujours sur les mêmes signaux.
  • Individuellement, chaque arbre peut faire des erreurs, voire du surapprentissage.

Mais quand on moyenne toutes ces estimations, les erreurs se compensent mutuellement. Les arbres qui surestiment compensent ceux qui sous-estiment. C’est ce qu’on appelle la réduction de variance par averaging, et c’est le mécanisme central qui rend le Random Forest régression si performant.

Implémentation Python avec scikit-learn

Exemple fondamental : RandomForestRegressor

import numpy as np
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score

# Generation de donnees synthetiques
np.random.seed(42)
n_samples = 1000
X = np.random.randn(n_samples, 5)
# Relation non-lineaire avec interactions
y = (2.5 * X[:, 0]**2
     + 1.8 * np.sin(X[:, 1])
     + 0.7 * X[:, 2] * X[:, 3]
     + 0.3 * X[:, 4]**3
     + np.random.randn(n_samples) * 0.5)

# Division entrainement / test
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)

# Entrainement du Random Forest regression
rf = RandomForestRegressor(
    n_estimators=200,
    max_depth=15,
    min_samples_split=5,
    min_samples_leaf=2,
    random_state=42,
    n_jobs=-1
)
rf.fit(X_train, y_train)

# Predictions et evaluation
y_pred = rf.predict(X_test)

print(f"MSE  : {mean_squared_error(y_test, y_pred):.4f}")
print(f"RMSE : {np.sqrt(mean_squared_error(y_test, y_pred)):.4f}")
print(f"MAE  : {mean_absolute_error(y_test, y_pred):.4f}")
print(f"R2   : {r2_score(y_test, y_pred):.4f}")

Comparaison avec un arbre de décision unique

Pour bien comprendre l’apport de l’approche ensembliste, comparons le Random Forest avec un seul arbre de décision :

from sklearn.tree import DecisionTreeRegressor

# Un seul arbre de decision
dt = DecisionTreeRegressor(max_depth=15, random_state=42)
dt.fit(X_train, y_train)
y_pred_dt = dt.predict(X_test)

# Random Forest
rf = RandomForestRegressor(n_estimators=200, max_depth=15, random_state=42)
rf.fit(X_train, y_train)
y_pred_rf = rf.predict(X_test)

print("=== Arbre de decision seul ===")
print(f"R2 train : {r2_score(y_train, dt.predict(X_train)):.4f}")
print(f"R2 test  : {r2_score(y_test, y_pred_dt):.4f}")
diff_dt = r2_score(y_train, dt.predict(X_train)) - r2_score(y_test, y_pred_dt)
print(f"Ecart    : {diff_dt:.4f} (surapprentissage)")
print()
print("=== Random Forest (200 arbres) ===")
print(f"R2 train : {r2_score(y_train, rf.predict(X_train)):.4f}")
print(f"R2 test  : {r2_score(y_test, y_pred_rf):.4f}")
diff_rf = r2_score(y_train, rf.predict(X_train)) - r2_score(y_test, y_pred_rf)
print(f"Ecart    : {diff_rf:.4f} (surapprentissage)")

L’arbre unique presente typiquement un surapprentissage marque (R2 excellent en entraînement mais nettement inferieur en test), alors que le Random Forest reduit considerablement cet ecart grace a l’averaging.

Importance des variables (Feature Importance)

Le Random Forest fournit une mesure naturelle de l’importance de chaque variable, basee sur la reduction moyenne de l’impurete (MSE) apportee par chaque variable a travers tous les arbres :

import pandas as pd

# Importance des variables
importances = rf.feature_importances_
indices = np.argsort(importances)[::-1]

feature_names = [f"Feature {i+1}" for i in range(5)]

print("=== Importance des variables ===")
for rank, idx in enumerate(indices, 1):
    print(f"  {rank}. {feature_names[idx]:12s} : {importances[idx]:.4f}")

Impact du nombre d’arbres (n_estimators)

L’un des avantages majeurs du Random Forest est que augmenter le nombre d’arbres ne provoque pas de surapprentissage. La courbe d’erreur converge simplement vers un plancher :

# Etude de l'impact de n_estimators
n_estimators_range = [5, 10, 25, 50, 100, 200, 500]
train_scores = []
test_scores = []

for n in n_estimators_range:
    rf_tmp = RandomForestRegressor(n_estimators=n, max_depth=15, random_state=42, n_jobs=-1)
    rf_tmp.fit(X_train, y_train)
    train_scores.append(r2_score(y_train, rf_tmp.predict(X_train)))
    test_scores.append(r2_score(y_test, rf_tmp.predict(X_test)))

print("=== Impact de n_estimators ===")
for n, tr, te in zip(n_estimators_range, train_scores, test_scores):
    print(f"  n={n:4d}  ->  R2 train: {tr:.4f}  R2 test: {te:.4f}")

On observe que le R2 en test s’ameliorerapidement jusqu’a environ 50-100 arbres, puis stabilise. C’est pourquoi des valeurs comme 100 a 300 arbres constituent un bon compromis entre performance et temps de calcul.

Donnees avec make_friedman1

Le jeu de donnees Friedman #1 est un benchmark classique pour la regression non-lineaire :

from sklearn.datasets import make_friedman1

X_f, y_f = make_friedman1(n_samples=1500, noise=1.0, random_state=42)
print(f"Forme de X : {X_f.shape}")  # (1500, 10)

# Seules les 5 premieres variables sont informatives
# Les 5 dernieres sont du bruit pur

Xf_train, Xf_test, yf_train, yf_test = train_test_split(
    X_f, y_f, test_size=0.2, random_state=42
)

rf_fried = RandomForestRegressor(n_estimators=200, random_state=42, n_jobs=-1)
rf_fried.fit(Xf_train, yf_train)
y_pred_fried = rf_fried.predict(Xf_test)
print(f"R2 test (Friedman1) : {r2_score(yf_test, y_pred_fried):.4f}")

# Verifions que le RF identifie correctement les variables importantes
importances_f = rf_fried.feature_importances_
for i, imp in enumerate(importances_f):
    statut = "informatif" if i < 5 else "bruit"
    print(f"  Variable {i:2d} ({statut:11s}) : importance = {imp:.4f}")

Les variables 5 a 9 (bruit pur) devraient obtenir des importances proches de zero, demonstrant la capacite du Random Forest a ignorer automatiquement les variables non informatives.

Hyperparametres cles du RandomForestRegressor

n_estimators

Le nombre d’arbres dans la foret. Augmenter cette valeur ameliore la stabilite et la performance jusqu’a convergence. Plus d’arbres = plus de temps de calcul, mais jamais de surapprentissage. Valeurs typiques : 100 a 500.

criterion

Le critere de qualite d’un split :

  • « squared_error«  (defaut) : minimise la variance (erreur quadratique moyenne). C’est le choix standard.
  • « absolute_error«  : minimise l’erreur absolue. Plus robuste aux valeurs aberrantes (outliers), mais souvent plus lent a converger.
  • « friedman_mse«  : variante du MSE avec correction de Friedman, qui peut produire de meilleurs splits dans certains cas.
  • « poisson«  : adapte aux donnees de comptage (valeurs entieres non-negatives).

max_depth

La profondeur maximale de chaque arbre. Limiter la profondeur empeche les arbres de devenir trop complexes et de memoriser le bruit. Pour le Random Forest, on peut souvent se permettre des arbres assez profonds (10-30) car le bagging et la selection aleatoire controlent deja le surapprentissage. Valeur par defaut : None (arbres developpes jusqu’a ce que toutes les feuilles soient pures ou contiennent min_samples_split echantillons).

min_samples_split

Le nombre minimum d’echantillons requis pour subdiviser un noeud interieur. Une valeur plus elevee (5, 10, 20) rend le modele plus conservateur et reduit le risque de surapprentissage sur des bruits locaux.

min_samples_leaf

Le nombre minimum d’echantillons requis dans une feuille. Controler ce parametre permet de lisser les predictions. Une feuille avec plusieurs echantillons donne une moyenne plus stable. Valeurs typiques : 1 a 5.

max_features

Le nombre maximum de variables considerees a chaque split. C’est le parametre le plus important pour la decorrelation des arbres :

  • « sqrt«  ou « auto«  : sqrt(p) variables (standard pour la classification, parfois utilise en regression).
  • « log2«  : log2(p) variables.
  • None : toutes les variables disponibles (equivalent a du bagging pur, sans selection aleatoire).
  • Un nombre fixe : par exemple max_features=3 ou un flottant comme 0.3 (30 % des variables).

Pour la regression, la valeur par defaut est 1.0 (toutes les variables), mais reduire a sqrt ou 1/3 peut ameliorer la generalisation sur des jeux de donnees a nombreuses variables.

bootstrap

Si True (defaut), chaque arbre est entraine sur un echantillon bootstrap. Si False, chaque arbre voit l’integralite du jeu d’entrainement (on obtient alors des Extremely Randomized Trees si max_features est aussi reduit).

oob_score

Si True, le score Out-Of-Bag est calcule automatiquement pendant l’entrainement. Utile pour l’evaluation sans jeu de validation separe :

rf_oob = RandomForestRegressor(
    n_estimators=300,
    oob_score=True,
    random_state=42,
    n_jobs=-1
)
rf_oob.fit(X_train, y_train)
print(f"R2 OOB : {rf_oob.oob_score_:.4f}")

random_state

La graine aleatoire pour la reproductibilite. Toujours la fixer dans un contexte experimental ou de production.

Avantages et limites du Random Forest regression

Avantages

  1. Pas de surapprentissage avec plus d’arbres : Augmenter n_estimators ne degrade jamais la performance, il suffit que le temps de calcul le permette.
  2. Peu de pretraitement necessaire : Pas besoin de normaliser ou standardiser les donnees. Le RF gere nativement des echelles heterogenes.
  3. Gestion automatique des interactions : Les arbres capturent naturellement les interactions non-lineaires entre variables sans qu’il soit necessaire de les specifier.
  4. Robustesse aux outliers : La moyenne des predictions est moins sensible aux valeurs extremes qu’une regression lineaire.
  5. Importance des variables integree : Pas besoin de procedure externe pour evaluer la contribution de chaque variable.
  6. Resistant au bruit dans les features : Les variables non informatives n’affectent pas significativement la performance.
  7. Evaluation OOB gratuite : Le score Out-Of-Bag fournit une estimation fiable de la generalisation sans jeu de validation.
  8. Fonctionne bien sur donnees tabulaires : Souvent competitif avec des methodes plus complexes sur des donnees structurees.

Limites

  1. Extrapolation impossible : Le RF ne peut pas predire en dehors de la plage des valeurs observees dans l’entrainement. Chaque feuille retourne une moyenne de valeurs d’entrainement, donc les predictions sont toujours bornees par le min/max du jeu d’entrainement.
  2. Predictions en escalier : La fonction de prediction est une fonction en marches d’escalier (piecewise constant), ce qui peut etre problematique si on attend une reponse lisse.
  3. Cout memoire et inference : Stocker des centaines d’arbres profonds consomme de la memoire. La prediction necessite de traverser tous les arbres.
  4. Moins performant que le boosting : Sur de nombreux benchmarks, le Gradient Boosting (XGBoost, LightGBM) ou les reseaux de neurones surpassent le Random Forest en precision pure.
  5. Difficile a interpreter : Contrairement a un arbre unique ou une regression lineaire, il est impossible de visualiser la regle complete d’un RF a 300 arbres.
  6. Biais vers les variables a nombreuses modalites : Les variables continues avec beaucoup de valeurs uniques ont tendance a obtenir des importances artificiellement elevees.

4 cas d’usage concrets

Cas d’usage 1 : Prediction de prix immobilier

Estimer le prix de vente d’un bien immobilier a partir de caracteristiques comme la surface, le nombre de pieces, l’annee de construction, le quartier et la distance aux transports. Le RF excelle ici grace aux interactions non-lineaires (par exemple, l’effet de la surface n’est pas le meme selon le quartier) et sa robustesse aux donnees manquantes via la moyenne des arbres.

Cas d’usage 2 : Prediction de consommation energetique

Predire la consommation electrique d’un batiment en fonction de la temperature exterieure, de l’humidite, de l’heure de la journee, du jour de la semaine et de caracteristiques du batiment. Les relations sont hautement non-lineaires (la consommation en climatisation n’est pas proportionnelle a la temperature), ce que le RF capture naturellement.

Cas d’usage 3 : Estimation de duree de trajet

Estimer le temps de trajet entre deux points en fonction de la distance, de l’heure, du jour, des conditions meteorologiques et du type de route. Le RF peut modeliser les interactions complexes (un embouteillage a 18h n’a pas le meme impact qu’a 14h) sans necessiter de feature engineering manuel.

Cas d’usage 4 : Prediction de rendement agricole

Estimer le rendement d’une culture (en tonnes par hectare) a partir de donnees meteorologiques (precipitations, temperature, ensoleillement), de caracteristiques du sol (pH, azote, matiere organique) et de pratiques culturales (irrigation, fertilisation). Le RF gere bien les relations complexes et les interactions entre de nombreuses variables heterogenes.

Bonnes pratiques et conseils

  1. Commencez par les valeurs par defaut : RandomForestRegressor() fonctionne deja bien en mode baseline. Ajustez ensuite progressivement.
  2. Utilisez OOB quand vos donnees sont limitees : oob_score=True permet de ne pas gaspiller de donnees pour la validation.
  3. Reglez max_features en premier : Si vous n’avez que le temps d’optimiser un seul hyperparametre, c’est celui-ci.
  4. Augmentez n_estimators jusqu’a stabilisation : Tracez la courbe OOB ou validation en fonction du nombre d’arbres pour trouver le point optimal.
  5. Combinez avec la validation croisee : cross_val_score avec KFold donne une estimation fiable et robuste de la performance.
  6. Ne normalisez pas inutilement : Contrairement aux regressions lineaires ou aux reseaux de neurones, le RF n’en a pas besoin.

Voir aussi

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur la façon dont les données de vos commentaires sont traitées.