Isolation Forest en Python : exemple, scores et limites

Isolation Forest : Guide Complet — Principes, Exemples et Implémentation Python

Isolation Forest repère des observations inhabituelles dans un tableau de données numériques. Avec scikit-learn, predict renvoie -1 pour une alerte et 1 pour une observation non signalée. Une alerte invite à examiner une ligne : elle ne prouve ni une erreur de saisie, ni une fraude, ni une panne.

Ce tutoriel pratique construit un exemple reproductible, explique la différence entre score_samples et decision_function, puis évalue les alertes sur un lot indépendant. Il complète notre présentation générale de la forêt d’isolation en se concentrant sur l’exécution et les pièges d’interprétation.

Niveau : connaître les tableaux NumPy et les fonctions Python. Les données de cette démonstration sont entièrement synthétiques ; aucun fichier externe ni service payant n’est nécessaire.

Comment fonctionne une forêt d’isolation ?

Imaginez un nuage de mesures regroupées autour de zéro et quelques mesures éloignées. L’algorithme découpe les données avec des variables et des seuils tirés au hasard. Un point éloigné peut être séparé du groupe après peu de découpes ; un point entouré de voisins en demande généralement davantage.

La forêt répète cette opération avec plusieurs arbres et combine les longueurs des chemins. Cette intuition explique pourquoi la méthode peut repérer des anomalies sans disposer d’étiquettes pendant l’entraînement. Elle ne garantit pas que tout phénomène rare sera détecté : le choix des variables et la distribution des données comptent. Voir le guide officiel de détection d’anomalies.

Deux usages doivent être distingués. Pour examiner un fichier existant, on peut ajuster le modèle sur ce fichier et classer ses lignes. Pour mesurer sa capacité à repérer de nouvelles observations, il faut réserver un autre lot. Nous suivons ce second cas ci-dessous.

Un exemple Python reproductible sur un nouveau lot

Environnement testé le 14 septembre 2026 : Python 3.12.14, NumPy 2.5.3, scikit-learn 1.9.1 et Matplotlib 3.11.2. Dans un environnement Python dédié, installer les versions utilisées :

python -m pip install "numpy==2.5.3" "scikit-learn==1.9.1" "matplotlib==3.11.2"

Copiez les quatre blocs Python dans le même fichier, dans l’ordre. Le premier crée un historique de 420 observations et un lot de test de 110 observations. Les deux variables sont fictives. Les points synthétiques éloignés servent uniquement à rendre le mécanisme observable.

import numpy as np
from sklearn.ensemble import IsolationForest

rng = np.random.default_rng(42)

# Un historique synthétique : 400 points ordinaires et 20 points éloignés.
X_train = np.vstack([
    rng.normal(0, 1, size=(400, 2)),
    rng.uniform(4, 6, size=(20, 2)),
])

# Un nouveau lot indépendant, jamais utilisé par fit.
X_test = np.vstack([
    rng.normal(0, 1, size=(100, 2)),
    rng.uniform(4, 6, size=(10, 2)),
])
# Étiquettes connues uniquement parce que les données sont synthétiques.
y_test = np.r_[np.zeros(100, dtype=int), np.ones(10, dtype=int)]

model = IsolationForest(
    n_estimators=200,
    max_samples="auto",
    contamination=0.05,  # Hypothèse fixée avant de regarder le test.
    random_state=42,
    n_jobs=1,
)
model.fit(X_train)

labels = model.predict(X_test)
scores = model.score_samples(X_test)
decisions = model.decision_function(X_test)
alertes = labels == -1

print("Observations de test :", len(X_test))
print("Alertes à examiner :", int(alertes.sum()))
print("Observations utilisées par arbre :", model.max_samples_)
print("Offset :", round(float(model.offset_), 4))

Sortie obtenue dans l’environnement indiqué :

Observations de test : 110
Alertes à examiner : 10
Observations utilisées par arbre : 256
Offset : -0.6311

Le paramètre contamination=0.05 exprime ici une hypothèse choisie à l’avance. Il ne signifie pas que 5 % de tous les futurs lots doivent déclencher une alerte. Le jeu de test n’intervient ni dans fit ni dans le choix de cette valeur.

Score, fonction de décision et étiquette : trois lectures différentes

  • score_samples(X) : les valeurs les plus basses correspondent aux observations les plus atypiques pour ce modèle.
  • decision_function(X) : le score après soustraction de offset_ ; une valeur strictement négative déclenche une alerte.
  • predict(X) : l’étiquette -1 ou 1 issue de ce seuil.

La relation est decision_function = score_samples - offset_. Avec contamination="auto", scikit-learn utilise un offset de -0.5 : il n’estime pas automatiquement la proportion réelle d’anomalies. Une contamination numérique règle le seuil à partir des scores d’entraînement. Ces conventions figurent dans la référence de l’API IsolationForest.

print("indice | score_samples | decision_function | alerte")
for i in np.argsort(scores)[:5]:
    print(f"{i:6d} | {scores[i]:13.4f} | {decisions[i]:17.4f} | {bool(alertes[i])}")

# Contrôle de la relation entre les deux méthodes.
assert np.allclose(decisions, scores - model.offset_)
assert np.array_equal(alertes, decisions < 0)
indice | score_samples | decision_function | alerte
   105 |       -0.7101 |           -0.0790 | True
   104 |       -0.6956 |           -0.0645 | True
   109 |       -0.6867 |           -0.0557 | True
   100 |       -0.6853 |           -0.0542 | True
   108 |       -0.6810 |           -0.0499 | True

Ces nombres ne sont pas des probabilités de panne ou de fraude. Un score de -0.65 ne signifie pas « 65 % de risque ». Utilisez le classement pour prioriser une inspection et choisissez votre règle d’alerte en fonction des erreurs acceptables.

Évaluer les alertes sur les données indépendantes

Nous connaissons les étiquettes parce que nous avons généré les données : 0 désigne le groupe ordinaire et 1 les anomalies synthétiques. Elles sont utilisées seulement maintenant pour comparer les prédictions à la construction du lot.

from sklearn.metrics import confusion_matrix, precision_score, recall_score

y_pred = alertes.astype(int)
matrice = confusion_matrix(y_test, y_pred, labels=[0, 1])
print("Matrice : lignes = réalité, colonnes = prédiction, ordre [0, 1]")
print(matrice)
print(f"Précision des alertes : {precision_score(y_test, y_pred, zero_division=0):.3f}")
print(f"Rappel des anomalies : {recall_score(y_test, y_pred, zero_division=0):.3f}")
Matrice : lignes = réalité, colonnes = prédiction, ordre [0, 1]
[[99  1]
 [ 1  9]]
Précision des alertes : 0.900
Rappel des anomalies : 0.900

Dans cet essai, 9 des 10 anomalies synthétiques sont signalées. Le bilan comprend 1 faux négatif et 1 faux positif. Les 99 autres observations ordinaires ne sont pas signalées. Il y a donc 10 alertes à examiner au total.

La précision indique quelle part des alertes correspond aux anomalies synthétiques ; le rappel indique quelle part des anomalies synthétiques est retrouvée. Les points de cet exemple sont volontairement faciles à distinguer. Les résultats ne prédisent pas la qualité du modèle sur des transactions, des capteurs ou vos propres fichiers.

Si vous réglez les variables ou le seuil en regardant ce résultat, ce lot devient de la validation. Gardez alors un autre test final. Apprenez aussi les éventuels prétraitements uniquement sur l’entraînement, puis appliquez-les aux autres lots. Pour des données temporelles, respectez l’ordre chronologique et les informations réellement disponibles au moment de l’alerte. Voir les recommandations scikit-learn sur les fuites de données.

Visualiser ce que le modèle signale

Le dernier bloc dessine les étiquettes synthétiques avec deux symboles et entoure les alertes en rouge. Une observation ordinaire entourée en rouge est un faux positif. Le fichier PNG est enregistré dans le dossier depuis lequel vous lancez le script.

import matplotlib.pyplot as plt

fig, ax = plt.subplots(figsize=(8, 5))
ax.scatter(X_test[y_test == 0, 0], X_test[y_test == 0, 1],
           color="#19768b", label="Ordinaires (générés)", s=32, alpha=0.75)
ax.scatter(X_test[y_test == 1, 0], X_test[y_test == 1, 1],
           color="#c57b16", marker="^", label="Anomalies (générées)", s=55)
ax.scatter(X_test[alertes, 0], X_test[alertes, 1], facecolors="none",
           edgecolors="#b92838", s=125, linewidths=1.4,
           label="Alertes du modèle")
ax.set(title="Isolation Forest : examiner les alertes sur un nouveau lot",
       xlabel="Variable 1 (synthétique)", ylabel="Variable 2 (synthétique)")
ax.legend(loc="upper left", framealpha=0.95, fontsize=9)
ax.grid(alpha=0.18)
fig.tight_layout()
fig.savefig("isolation-forest-test.png", dpi=160)
plt.close(fig)
Lot de test synthétique : les cercles rouges signalent les alertes, y compris les faux positifs.
Données générées pour cet article. Les symboles indiquent la construction du lot ; les cercles rouges montrent les alertes du modèle.

Les réglages à comprendre avant d’expérimenter

Paramètre Dans notre exemple À retenir
n_estimators 200 Nombre d’arbres. Comparer stabilité des résultats et temps de calcul avant d’en ajouter.
max_samples "auto" Le défaut utilise min(256, n_samples) observations par arbre.
contamination 0.05 Hypothèse pour régler le seuil, pas étiquette de vérité.
max_features 1.0, défaut Sous-échantillon de variables par arbre. Le réduire n’est pas une garantie d’accélération.
random_state 42 Fixe l’aléa du modèle. L’aléa des données est fixé séparément.

Commencez par un exemple maîtrisé et ne changez qu’un choix à la fois. Dans nos contrôles, modifier seulement contamination de 0.05 à 0.15, à données et graine identiques, conserve les scores bruts mais modifie l’offset. Augmenter le nombre d’alertes ne rend donc pas nécessairement la détection meilleure.

Les erreurs qui rendent les résultats trompeurs

Normaliser systématiquement « pour éviter que la grande variance domine »

Isolation Forest ne sélectionne pas une variable parce que sa variance est la plus élevée : le choix des variables est aléatoire. Il ne faut donc pas justifier une normalisation par cette affirmation. Notre démonstration fonctionne sans StandardScaler. Un contrôle complémentaire sur ces mêmes données donne des scores identiques à la précision numérique après standardisation.

Ce contrôle n’est pas une garantie pour tout prétraitement. Une transformation non linéaire, un encodage de catégories ou un changement dans les données peut modifier le problème. Décidez du prétraitement en fonction de la signification des colonnes, et réévaluez le résultat.

Transformer une alerte en suppression automatique

Une ligne inhabituelle peut être valide et précieuse. Conservez les données d’origine, ajoutez une colonne d’alerte et examinez les cas signalés. Supprimer les lignes avant toute analyse peut retirer précisément le phénomène que vous cherchez à comprendre.

Présenter une évaluation sur l’entraînement comme une performance future

Un classement du fichier utilisé par fit décrit ce fichier. Il ne remplace pas une évaluation indépendante. Une graine fixe rend un essai reproductible ; elle ne rend pas automatiquement ses conclusions généralisables.

Promettre un gain de vitesse universel

Un chronométrage sur un petit jeu ne démontre pas qu’une méthode sera dix ou cent fois plus rapide ailleurs. Comparez sur vos dimensions, votre matériel et des réglages documentés, en regardant aussi la qualité des alertes. Évitez de multiplier les arbres ou les variantes sans question précise à résoudre.

Quand cette approche est-elle utile ?

Pour commencer, choisissez un usage où une personne peut examiner les alertes : contrôle de mesures de capteurs, valeurs inhabituelles dans un export, ou variations de volumes dans des journaux techniques. Utilisez un nom tel que a_examiner plutôt que est_fraude ou est_en_panne.

Si la notion d’anomalie dépend d’un contexte, ajoutez des variables pertinentes ou comparez des observations réellement comparables. Si vous cherchez avant tout des groupes, explorez le guide HDBSCAN : un objectif de regroupement ne se confond pas avec la recherche d’observations à examiner.

Passer à un fichier CSV : notre projet Python pour détecter des lignes inhabituelles dans un CSV fournit un script complet, des mesures synthétiques et un résultat exporté en conservant les identifiants et les lignes incomplètes. Télécharger les fichiers gratuits du projet CSV (ZIP).

Trois exercices pour continuer

  1. Lire une matrice de confusion. Retrouvez à la main le nombre d’alertes à partir des quatre cases, puis recalculez précision et rappel.
  2. Étudier le seuil. Sur un lot de validation séparé, comparez 0.02, 0.05 et 0.10. Notez les alertes ajoutées, sans choisir votre réglage sur le test final.
  3. Préserver la traçabilité. Associez un identifiant aux observations et vérifiez que les cinq indices classés comme les plus atypiques correspondent toujours aux bonnes lignes.

Pour consolider les bases avant ces exercices, consultez notre parcours de ressources Python gratuites et de livres par niveau. Le code de ce tutoriel suffit pour reproduire la démonstration.

Un livre pour structurer la suite de l’apprentissage

Machine Learning avec Scikit-Learn, Aurélien Géron, 3e édition, Dunod, ISBN 9782100847686. D’après le sommaire de l’éditeur, le livre traite notamment du déroulement d’un projet, de l’évaluation, des arbres et de l’apprentissage non supervisé. C’est une piste si vous connaissez déjà Python et souhaitez une progression plus large que ce seul tutoriel. Il ne se limite pas à Isolation Forest.

La sélection repose sur la fiche éditeur consultée le 14 septembre 2026, pas sur une lecture intégrale revendiquée. Consultez l’extrait et les versions utilisées dans les notebooks avant de choisir. Les versions du livre et celles testées ici peuvent différer.

Affiliation : le lien Amazon ci-dessous est affilié. En tant que Partenaire Amazon, je réalise un bénéfice sur les achats remplissant les conditions requises.

Consulter le sommaire et l’extrait chez Dunod · Rechercher cette édition sur Amazon — lien affilié

Le lien ouvre une recherche par ISBN. Vérifiez l’édition, le format, le prix et la disponibilité chez le vendeur avant un achat.

Questions fréquentes

Faut-il des exemples d’anomalies pour entraîner le modèle ?

Les appels à fit de ce tutoriel utilisent uniquement les variables. Les étiquettes synthétiques servent à l’évaluation. Sans étiquettes réelles, faites examiner un échantillon des alertes et documentez ce que vous pouvez effectivement vérifier.

Pourquoi obtient-on plus ou moins de 5 % d’alertes sur le test ?

Le seuil est déterminé à l’entraînement. La distribution du nouveau lot et ses scores peuvent être différents. Le nombre d’alertes observé sur le test ne constitue pas une estimation automatique de son taux réel d’erreurs.

Puis-je utiliser l’exemple directement en production ?

Il sert à comprendre et à reproduire le mécanisme. Avant un usage réel, vérifier la préparation des données, la stabilité du seuil, les erreurs acceptables et le suivi des changements de distribution. Une démonstration sur deux variables synthétiques ne valide pas ces choix.

Exemples exécutés et guide révisé le 14 septembre 2026. Les résultats numériques correspondent aux données et versions indiquées ; les liens techniques renvoient aux documentations officielles.