Courbe AUC - ROC
Calculez et tracez des courbes AUC-ROC en Python avec sklearn. Comprenez TPR, FPR, seuils et quand utiliser l'AUC plutôt que la précision.
La courbe AUC-ROC (Aire sous la courbe des caractéristiques opératives du récepteur) est l'une des métriques les plus importantes pour évaluer les modèles de classification binaire. Elle mesure la capacité d'un modèle à séparer les exemples positifs des exemples négatifs pour chaque seuil de décision possible, offrant une image bien plus riche qu'un simple score de précision.
Ce chapitre couvre :
- Ce qu'est la courbe ROC et comment elle est construite
- Comment lire le TPR, le FPR et les termes de la matrice de confusion qui les sous-tendent
- Comment calculer l'AUC-ROC avec
scikit-learnen Python - Comment tracer la courbe ROC avec
matplotlib - Quand l'AUC-ROC est la bonne métrique et quand elle ne l'est pas
Termes clés : TP, FP, TN, FN
Avant d'aborder la courbe elle-même, il est important de comprendre les quatre résultats qu'un classifieur binaire peut produire. Pour toute prédiction, l'étiquette réelle est soit positive (P) soit négative (N), et l'étiquette prédite est soit positive soit négative :
| Prédit positif | Prédit négatif | |
|---|---|---|
| Réel positif | Vrai Positif (TP) | Faux Négatif (FN) |
| Réel négatif | Faux Positif (FP) | Vrai Négatif (TN) |
Ces quatre cellules constituent les éléments de base de chaque métrique d'évaluation abordée dans ce chapitre. Pour une introduction plus approfondie, consultez le chapitre Matrice de confusion.
Qu'est-ce que la courbe ROC ?
Un classifieur génère généralement un score de probabilité (un nombre entre 0 et 1) plutôt qu'une étiquette directe. Vous choisissez un seuil — par exemple 0,5 — et tout ce qui dépasse ce seuil est prédit comme positif.
Modifier le seuil déplace l'équilibre entre la détection de vrais positifs et le signalement accidentel de vrais négatifs :
- Un seuil très bas détecte plus de positifs (rappel élevé) mais produit également plus de fausses alarmes.
- Un seuil très élevé est sélectif (haute précision) mais rate des positifs réels.
La courbe ROC représente graphiquement ce compromis pour chaque seuil possible à la fois :
- Axe X — Taux de Faux Positifs (FPR) : quelle fraction des négatifs réels est incorrectement signalée comme positive.
- Axe Y — Taux de Vrais Positifs (TPR), aussi appelé Rappel ou Sensibilité : quelle fraction des positifs réels est correctement identifiée.
TPR = TP / (TP + FN) et FPR = FP / (FP + TN)
Chaque point sur la courbe ROC correspond à un paramètre de seuil. Ensemble, ils tracent un chemin de (0, 0) — le seuil le plus sélectif, ne prédisant rien de positif — à (1, 1) — le seuil le moins sélectif, prédisant tout comme positif.
Qu'est-ce que l'AUC ?
L'AUC (Aire sous la courbe) résume toute la courbe ROC en un seul nombre compris entre 0 et 1 :
| AUC | Signification |
|---|---|
| 1.0 | Classifieur parfait — sépare chaque positif de chaque négatif |
| 0.5 | Aucune compétence — équivalent à une supposition aléatoire |
| < 0.5 | Pire que le hasard (vos probabilités prédites sont inversées) |
| 0.7 – 0.8 | Acceptable pour de nombreux problèmes pratiques |
| 0.8 – 0.9 | Bon |
| > 0.9 | Excellent |
Intuitivement, l'AUC est la probabilité que le modèle classe un exemple positif choisi aléatoirement plus haut qu'un exemple négatif choisi aléatoirement.
Calculer l'AUC-ROC avec scikit-learn
Le module sklearn.metrics fournit roc_curve() pour obtenir les valeurs TPR/FPR seuil par seuil et roc_auc_score() pour obtenir le nombre AUC unique.
Exemple minimal fonctionnel
from sklearn.datasets import make_classification
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_auc_score, roc_curve
# 1. Create a toy binary-classification dataset
X, y = make_classification(n_samples=500, n_features=10, random_state=42)
# 2. Split into train / test sets
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.3, random_state=42
)
# 3. Train a logistic regression model
model = LogisticRegression(random_state=42)
model.fit(X_train, y_train)
# 4. Get probability scores for the positive class (column 1)
y_proba = model.predict_proba(X_test)[:, 1]
# 5. Compute AUC
auc = roc_auc_score(y_test, y_proba)
print(f"AUC-ROC: {auc:.3f}")
# 6. Get the (fpr, tpr, thresholds) arrays for plotting
fpr, tpr, thresholds = roc_curve(y_test, y_proba)
print(f"Number of threshold points: {len(thresholds)}")La sortie sera proche de :
AUC-ROC: 0.944
Number of threshold points: 30La valeur exacte varie légèrement selon votre version de scikit-learn, mais elle devrait se situer dans la plage 0,90–0,97 pour ce jeu de données.
Tracer la courbe ROC
import matplotlib.pyplot as plt
from sklearn.datasets import make_classification
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_auc_score, roc_curve
X, y = make_classification(n_samples=500, n_features=10, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
model = LogisticRegression(random_state=42)
model.fit(X_train, y_train)
y_proba = model.predict_proba(X_test)[:, 1]
auc = roc_auc_score(y_test, y_proba)
fpr, tpr, _ = roc_curve(y_test, y_proba)
plt.figure(figsize=(7, 5))
plt.plot(fpr, tpr, color="steelblue", lw=2, label=f"ROC curve (AUC = {auc:.2f})")
plt.plot([0, 1], [0, 1], color="gray", linestyle="--", label="Random baseline (AUC = 0.50)")
plt.xlabel("False Positive Rate (FPR)")
plt.ylabel("True Positive Rate (TPR)")
plt.title("ROC Curve")
plt.legend(loc="lower right")
plt.tight_layout()
plt.savefig("roc_curve.png", dpi=120)
plt.show()La ligne diagonale en pointillés représente un classifieur aléatoire. Plus la courbe ROC s'incurve vers le coin supérieur gauche, meilleur est le modèle.
Comparer plusieurs modèles
Un flux de travail courant consiste à entraîner plusieurs modèles et à comparer leurs courbes ROC sur le même graphique :
from sklearn.datasets import make_classification
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_auc_score, roc_curve
import matplotlib.pyplot as plt
X, y = make_classification(n_samples=500, n_features=10, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
models = {
"Logistic Regression": LogisticRegression(random_state=42),
"Decision Tree": DecisionTreeClassifier(max_depth=3, random_state=42),
}
plt.figure(figsize=(7, 5))
for name, clf in models.items():
clf.fit(X_train, y_train)
y_proba = clf.predict_proba(X_test)[:, 1]
fpr, tpr, _ = roc_curve(y_test, y_proba)
auc = roc_auc_score(y_test, y_proba)
plt.plot(fpr, tpr, lw=2, label=f"{name} (AUC = {auc:.2f})")
plt.plot([0, 1], [0, 1], "k--", label="Random (AUC = 0.50)")
plt.xlabel("False Positive Rate")
plt.ylabel("True Positive Rate")
plt.title("ROC Curve Comparison")
plt.legend(loc="lower right")
plt.tight_layout()
plt.savefig("roc_comparison.png", dpi=120)
plt.show()Le modèle avec la plus grande aire sous sa courbe est généralement le meilleur choix pour ce jeu de données. Pour un flux de sélection de modèle rigoureux, combinez cela avec la validation croisée.
Choisir un point de fonctionnement (seuil)
L'AUC résume tous les seuils, mais vous devrez finalement en choisir un pour la production. Deux stratégies courantes :
1. Statistique J de Youden
Le J de Youden maximise TPR − FPR, trouvant le point unique sur la courbe ROC le plus éloigné de la diagonale :
from sklearn.datasets import make_classification
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_curve
import numpy as np
X, y = make_classification(n_samples=500, n_features=10, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
model = LogisticRegression(random_state=42)
model.fit(X_train, y_train)
y_proba = model.predict_proba(X_test)[:, 1]
fpr, tpr, thresholds = roc_curve(y_test, y_proba)
j_scores = tpr - fpr
best_idx = int(np.argmax(j_scores))
best_threshold = thresholds[best_idx]
print(f"Best threshold (Youden's J): {best_threshold:.3f}")
print(f"TPR at best threshold: {tpr[best_idx]:.3f}")
print(f"FPR at best threshold: {fpr[best_idx]:.3f}")2. Seuil guidé par les besoins métier
Dans la détection de fraude, vous pouvez tolérer plus de faux positifs pour attraper davantage de fraudes (seuil plus bas). Dans le dépistage médical, vous pouvez vouloir très peu de faux négatifs (également seuil plus bas). Le choix du seuil est en fin de compte une décision métier éclairée par le coût de chaque type d'erreur.
AUC-ROC vs. autres métriques
| Métrique | Idéale quand... | Attention à... |
|---|---|---|
| Accuracy | Les classes sont équilibrées | Trompeuse sur des jeux de données déséquilibrés |
| Précision / Rappel | Vous vous souciez principalement d'une classe | Nécessite un seuil |
| F1-Score | Équilibre harmonique de la précision et du rappel | Toujours dépendante du seuil |
| AUC-ROC | Comparer des modèles ou ajuster les seuils | Non significative pour plusieurs classes sans extension |
| AUC-PR (Précision-Rappel AUC) | Fort déséquilibre de classes (positifs rares) | Moins intuitive que ROC |
Pour des données fortement déséquilibrées — disons 1 % de positifs — la courbe AUC-PR (précision vs. rappel) est souvent plus informative que l'AUC-ROC, car le FPR peut sembler faible même lorsque de nombreux négatifs sont incorrectement signalés.
Erreurs courantes
Passer des étiquettes directes au lieu de probabilités. roc_auc_score a besoin de scores de probabilité, pas d'étiquettes 0/1. Utilisez model.predict_proba(X_test)[:, 1], pas model.predict(X_test).
Oublier de spécifier la classe positive. Par défaut, roc_curve et roc_auc_score traitent l'étiquette entière la plus grande comme positive. Passez pos_label=1 explicitement lorsque vos étiquettes ne sont pas des entiers 0/1.
Surajustement à l'AUC sur l'ensemble d'entraînement. Évaluez toujours sur un ensemble de test réservé ou utilisez la validation croisée pour obtenir une estimation d'AUC fiable. Le chapitre Recherche sur grille montre comment passer scoring='roc_auc' directement à GridSearchCV.
AUC ≈ 0,5 ne signifie pas toujours que le modèle est mauvais. Cela peut signifier que les exemples positifs et négatifs se chevauchent réellement dans l'espace des caractéristiques, ou que vos caractéristiques ne sont pas informatives pour la tâche.
Exemple pratique : prédiction de maladie
L'exemple de bout en bout suivant utilise le jeu de données sur le cancer du sein fourni avec scikit-learn :
from sklearn.datasets import load_breast_cancer
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import roc_auc_score, roc_curve
import matplotlib.pyplot as plt
# Load dataset (569 samples, 30 features, binary labels: malignant=0 / benign=1)
data = load_breast_cancer()
X, y = data.data, data.target
# Scale features — important for logistic regression
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
X_train, X_test, y_train, y_test = train_test_split(
X_scaled, y, test_size=0.2, random_state=42, stratify=y
)
classifiers = {
"Logistic Regression": LogisticRegression(max_iter=1000, random_state=42),
"Random Forest": RandomForestClassifier(n_estimators=100, random_state=42),
}
plt.figure(figsize=(7, 5))
for name, clf in classifiers.items():
clf.fit(X_train, y_train)
y_proba = clf.predict_proba(X_test)[:, 1]
auc = roc_auc_score(y_test, y_proba)
fpr, tpr, _ = roc_curve(y_test, y_proba)
plt.plot(fpr, tpr, lw=2, label=f"{name} (AUC = {auc:.3f})")
plt.plot([0, 1], [0, 1], "k--", label="Random (AUC = 0.50)")
plt.xlabel("False Positive Rate")
plt.ylabel("True Positive Rate")
plt.title("ROC Curve — Breast Cancer Dataset")
plt.legend(loc="lower right")
plt.tight_layout()
plt.savefig("breast_cancer_roc.png", dpi=120)
plt.show()Les deux classifieurs devraient produire des scores AUC supérieurs à 0,98 sur ce jeu de données, confirmant que les caractéristiques du cancer du sein sont très prédictives.
Sujets connexes
- Matrice de confusion — les éléments de base TP/FP/TN/FN utilisés tout au long de ce chapitre
- Régression logistique — le modèle le plus courant associé à l'évaluation AUC-ROC
- Validation croisée — comment obtenir des estimations d'AUC fiables qui se généralisent au-delà d'une seule division entraînement/test
- Recherche sur grille — comment ajuster les hyperparamètres avec
scoring='roc_auc' - Arbre de décision — un autre classifieur binaire dont les sorties de probabilité peuvent être évaluées avec l'AUC-ROC
Résumé
| Concept | Point clé |
|---|---|
| Courbe ROC | Trace le TPR vs. FPR à chaque seuil de décision |
| AUC | Aire sous la courbe ROC ; 1,0 = parfait, 0,5 = aléatoire |
roc_auc_score | Passer des scores de probabilité, pas des étiquettes directes |
roc_curve | Retourne les tableaux (fpr, tpr, thresholds) pour le tracé |
| Sélection du seuil | Utiliser le J de Youden ou la connaissance du domaine pour choisir un seuil de production |
| Quand préférer AUC-PR | Jeux de données fortement déséquilibrés avec des positifs rares |
L'AUC-ROC vous donne un nombre unique, indépendant du seuil, qui résume la capacité discriminative de votre modèle sur tous les points de fonctionnement. Utilisez-le pour comparer des modèles, ajuster les hyperparamètres et communiquer la qualité du classifieur — puis choisissez le seuil spécifique qui correspond à la tolérance de votre application aux faux positifs versus les faux négatifs.