L’importance des variables Random Forest peut placer une colonne aléatoire devant le vrai signal. Ce n’est pas la preuve que le hasard explique la cible. L’importance calculée pendant l’apprentissage et la contribution aux prédictions sur des observations indépendantes ne mesurent pas la même chose.
Nous construisons un témoin aléatoire à forte cardinalité, puis comparons feature_importances_ et permutation_importance sur dix jeux synthétiques. Les dix graines sont conservées dans les résultats : aucune n’est sélectionnée pour obtenir une figure spectaculaire.
Trois variables dont une seule porte le signal
Chaque jeu contient 1 800 lignes. La première variable, binaire, porte la cible ; nous inversons aléatoirement cette cible avec une probabilité de 20 %, ce qui introduit du bruit. Les deux autres variables sont tirées indépendamment : un nombre continu, presque toujours unique par ligne, et un autre nombre binaire.
Nous apprenons une forêt de 120 arbres sur 60 % des lignes, puis évaluons sur les 40 % restants. Les arbres ne sont pas limités en profondeur. Ce choix volontaire permet d’observer le surapprentissage : la forêt peut exploiter des séparations accidentelles dans le bruit continu.
Le protocole est répété avec les graines 0 à 9. Pour chaque forêt, la permutation est calculée dix fois par variable sur le lot indépendant, avec l’accuracy comme score. Nous ne sélectionnons ni variables ni hyperparamètres à partir de ce lot dans l’expérience.
Le bruit domine la MDI, le signal domine la permutation
| Variable | MDI moyenne | Perte d’accuracy par permutation | Étendue de cette perte sur 10 graines |
|---|---|---|---|
| Signal binaire | 0,3648 | 0,1814 | 0,1610 à 0,2004 |
| Bruit continu | 0,6310 | 0,0031 | -0,0179 à 0,0161 |
| Bruit binaire | 0,0042 | -0,0027 | -0,0122 à 0,0196 |
Le bruit continu reçoit en moyenne environ 63,10 % de l’importance MDI, contre 36,48 % pour le signal binaire. Pourtant, le mélanger sur le test ne réduit l’accuracy que d’environ 0,31 point de pourcentage en moyenne. Mélanger le signal coûte environ 18,14 points.
La forêt atteint une accuracy moyenne de 99,98 % à l’apprentissage et de 68,01 % au test. Cet écart est cohérent avec un modèle qui mémorise beaucoup de variations accidentelles. Le jeu a été conçu pour montrer ce mécanisme ; ces nombres ne sont pas une performance typique de Random Forest sur un problème réel.

Pourquoi les deux importances divergent
La MDI additionne les réductions d’impureté obtenues dans les arbres pendant l’apprentissage, puis les normalise. Une variable continue offre de nombreux seuils possibles. Elle peut donc expliquer des particularités du jeu d’apprentissage, même lorsque son générateur est indépendant de la cible.
La permutation pose une autre question : de combien baisse le score de ce modèle, sur ce jeu, quand on mélange une colonne ? La démonstration officielle scikit-learn sur l’importance par permutation détaille notamment les limites de la MDI pour les variables à forte cardinalité.
Les unités diffèrent. Une importance MDI de 0,63 est une part de réduction d’impureté ; une permutation de 0,0031 est une différence d’accuracy, soit 0,31 point de pourcentage. Les deux panneaux ont donc des échelles séparées. On ne doit pas soustraire ces valeurs ou les interpréter comme les mêmes pourcentages.
Les barres d’étendue montrent le minimum et le maximum des dix réalisations synthétiques, pas un intervalle de confiance. Une petite importance négative peut apparaître lorsque le mélange améliore légèrement le score observé. Elle ne prouve pas un effet causal bénéfique du bruit.
Reproduire les dix répétitions
Télécharger le code et les fichiers — ZIP gratuit. Archive sans inscription, 4 tests, vérifiée après extraction. Dans un environnement Python dédié, installez python -m pip install -r requirements.txt, puis exécutez python importance.py et python test_exemple.py. Le programme fonctionne localement après installation et ne transmet aucune donnée.
Le ZIP contient les résultats de toutes les graines, les scores d’apprentissage et de test, le résumé des importances et la figure. Quatre tests contrôlent la séparation des lignes, les cardinalités, la normalisation de la MDI et le calcul des moyennes de permutation à partir des dix répétitions.
Afficher le script Python complet
"""Importance MDI et permutation : dix répétitions préfixées, données synthétiques."""
from pathlib import Path
import json
import numpy as np
import pandas as pd
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
from sklearn.ensemble import RandomForestClassifier
from sklearn.inspection import permutation_importance
from sklearn.model_selection import train_test_split
def repetition(graine):
rng = np.random.default_rng(graine)
signal = rng.integers(0, 2, 1800)
y = np.bitwise_xor(signal, rng.random(1800) < 0.2)
X = pd.DataFrame({"signal_binaire": signal,
"bruit_continu": rng.normal(size=1800),
"bruit_binaire": rng.integers(0, 2, 1800)})
train, test = train_test_split(np.arange(len(y)), test_size=0.4,
stratify=y, random_state=graine)
modele = RandomForestClassifier(n_estimators=120, random_state=graine,
n_jobs=1).fit(X.iloc[train], y[train])
perm = permutation_importance(modele, X.iloc[test], y[test],
n_repeats=10, random_state=100 + graine,
scoring="accuracy", n_jobs=1)
lignes = [{"graine": graine, "variable": nom,
"mdi": float(modele.feature_importances_[i]),
"permutation": float(perm.importances_mean[i]),
"ecart_type_permutations": float(perm.importances_std[i])}
for i, nom in enumerate(X.columns)]
scores = {"graine": graine, "accuracy_train": float(modele.score(X.iloc[train], y[train])),
"accuracy_test": float(modele.score(X.iloc[test], y[test]))}
audit = {"train": train, "test": test, "X": X, "permutations": perm.importances}
return lignes, scores, audit
def main():
dossier = Path(__file__).resolve().parent
lignes, scores = [], []
for graine in range(10):
l, s, _ = repetition(graine)
lignes.extend(l)
scores.append(s)
table = pd.DataFrame(lignes)
table.to_csv(dossier / "importances-dix-graines.csv", index=False)
pd.DataFrame(scores).to_csv(dossier / "scores-dix-graines.csv", index=False)
resume = table.groupby("variable")[["mdi", "permutation"]].agg(["mean", "min", "max"])
resume.to_csv(dossier / "resume-importances.csv")
resultats = {"graines": list(range(10)), "repetitions_permutation": 10,
"scores_moyens": pd.DataFrame(scores).drop(columns="graine").mean().to_dict(),
"importances": {nom: {f"{m}_{stat}": float(v) for (m, stat), v in ligne.items()}
for nom, ligne in resume.iterrows()}}
fig, axes = plt.subplots(1, 2, figsize=(10, 4.4), layout="constrained")
for ax, mesure, titre in zip(axes, ["mdi", "permutation"],
["MDI : part de réduction d'impureté", "Permutation : perte d'accuracy au test"]):
g = table.groupby("variable")[mesure].agg(["mean", "min", "max"])
ax.barh(g.index, g["mean"], color=["#dd7832", "#728aa1", "#148c93"])
ax.errorbar(g["mean"], np.arange(len(g)),
xerr=np.array([g["mean"] - g["min"], g["max"] - g["mean"]]),
fmt="none", color="#172c42", capsize=4)
ax.axvline(0, color="gray", linewidth=0.8)
ax.set_title(titre, fontsize=10)
fig.suptitle("Dix jeux synthétiques : moyenne et étendue observée")
fig.savefig(dossier / "figure.png", dpi=160)
plt.close(fig)
texte = json.dumps(resultats, ensure_ascii=False, indent=2)
(dossier / "resultats.json").write_text(texte + "\n", encoding="utf-8")
print(texte)
if __name__ == "__main__":
main()
Transformer le diagnostic en décision de modélisation
Avant de commenter une importance, vérifiez que le modèle prédit suffisamment bien sur des observations adaptées à son futur usage. Puis confrontez l’importance d’apprentissage à une mesure indépendante. Ajouter une colonne témoin aléatoire peut aider à détecter un signal d’alarme, mais son classement ne constitue pas une règle universelle de suppression des variables.
Si ce diagnostic vous conduit à retirer une variable, limiter la profondeur ou modifier min_samples_leaf, vous utilisez ce lot pour prendre une décision. Il devient alors un lot de validation : conservez un autre test final pour évaluer la version choisie. Répéter les modifications jusqu’à obtenir un bon score sur le même test réintroduirait un biais.
Enfin, une permutation faible ne signifie pas toujours qu’une information est inutile. Une autre colonne peut fournir le même signal et compenser son mélange. Ce problème est traité séparément dans notre cas de permutation groupée des variables redondantes. Il est distinct du bruit indépendant utilisé ici.
Pour les paramètres de la forêt, consultez le guide Random Forest. Les scripts de la série sont disponibles dans les ressources Python gratuites.
Questions fréquentes
Une forte importance prouve-t-elle une relation causale ?
Non. Ici, une variable indépendante de la cible reçoit la plus forte MDI. Même une importance sur un lot indépendant décrit l’usage d’une information par un modèle, pas l’effet d’une intervention sur cette information.
Dois-je abandonner feature_importances_ ?
Vous pouvez la conserver comme diagnostic de l’apprentissage, en annonçant ce qu’elle mesure. Pour discuter l’utilité prédictive, confrontez-la à la performance indépendante et à une permutation adaptée au problème.
Exemple original exécuté le 21 octobre 2026 avec Python 3.12.14. numpy 2.5.3, pandas 3.0.6, scikit-learn 1.9.1, matplotlib 3.11.2, scipy 1.18.1. Les versions testées figurent dans le téléchargement. Miniature illustrative générée avec image_gen ; les résultats présentés proviennent du code exécuté. Notre méthode éditoriale.

