Le machine learning en partant de zéro · Leçon 2.3 · 10 sur 33 leçons prêtes · 12 min
Seuil, ROC et PR : tous les seuils à la fois
En bref
Les courbes ROC et PR montrent tous les seuils. Si une classe est rare, le ROC AUC bouge à peine et l’AP chute : les fausses alertes mangent la précision.
Échauffement Deux questions de leçons précédentes. Une minute, sans jamais bloquer la leçon.
Dans la leçon 2.2, vous déplaciez un seuil et regardiez la matrice de confusion changer. Chaque seuil est une décision différente, même si les scores du modèle restent les mêmes. Aujourd’hui, vous verrez tous les seuils à la fois, sur deux courbes : ROC et précision–rappel (PR). Vous vérifierez aussi laquelle dit la vérité quand les malades sont peu nombreux. Le modèle est faible exprès : une régression logistique qui ne voit qu’une mesure, la texture moyenne de la tumeur, pour que les courbes ne collent pas aux coins.
Choisissez une réponse et votre degré de certitude.
Répondez pour débloquer le labo.
Labo interactif
Ce labo interactif fonctionne dans un navigateur avec JavaScript activé. Le texte qui l’entoure décrit ce qu’il montre.
Voir la réponse
Bonne réponse : Le ROC AUC change à peine (environ 0,77), tandis que l’AP tombe vers 0,14
Le ROC AUC vaut 0,773 avec toutes les malignes et 0,772 en moyenne avec 19 (sur 200 tirages des malignes conservées). L’AP tombe de 0,591 à 0,137 en moyenne. Le modèle n’a rien oublié ; seules les proportions des classes ont changé. La ROC ne le voit pas, la courbe PR le voit.
À vous de jouer
- Commencez avec 212 malignes et le seuil 0,5. Lisez le rappel et le FPR, puis déplacez le seuil à 0,3. Dans quelle direction va le point sur les deux courbes ?
- Passez à 19 malignes au seuil 0,3. Il y a autant de fausses alertes qu’à l’instant. Qu’est-il arrivé à la précision ?
- Comparez le ROC AUC et l’AP avec 212, 40 et 19 malignes.
Une fois vérifié dans le lab, nommons ce que vous voyez.
L’idée en quelques mots
Le modèle ne dit pas « maligne » ou « bénigne ». Il donne un score de 0 à 1, et c’est un seuil qui décide. Chaque seuil donne une autre paire de nombres : combien de malignes ont été trouvées (rappel) et combien de bénignes ont reçu une fausse alerte. La courbe ROC trace ces paires pour tous les seuils à la fois : à l’horizontale, la part de fausses alertes parmi les bénignes (FPR) ; à la verticale, le rappel. Un seuil élevé, c’est le coin inférieur gauche (peu d’alertes) ; un seuil bas, le coin supérieur droit (une alerte pour chaque biopsie).
La courbe précision–rappel (PR) montre les mêmes seuils autrement : à l’horizontale, le rappel ; à la verticale, la précision, c’est-à-dire la part des alertes qui sont justes. L’aire sous la courbe ROC est le ROC AUC, l’aire sous la courbe PR est l’AP (average precision). Chacun résume tous les seuils à la fois, donc ne dépend pas du seuil que vous choisissez.
Sur les 569 biopsies, le modèle a un ROC AUC de 0,773 et un AP de 0,591. Deviner au hasard donnerait un ROC AUC de 0,5 et un AP égal à la part de malignes, soit 0,373. Le modèle fait nettement mieux que le hasard, mais reste loin de l’idéal, qui vaut 1.
Jak to policzono
- Biopsies : Breast Cancer Wisconsin (Diagnostic), UCI, licence CC BY 4.0. 569 biopsies (357 bénignes, 212 malignes). Le modèle voit une mesure : la texture moyenne de la tumeur.
- Scores issus d’une validation croisée en 5 parties (
StratifiedKFold(5)dans scikit-learn) : chaque biopsie est notée par un modèle qui ne l’a jamais vue. - Classe plus rare : on garde les 357 bénignes et 40 ou 19 malignes tirées au hasard. Le graphique montre un tirage ; les moyennes portent sur 200 tirages.
- Modèle : standardisation et régression logistique (C = 1).
Pourquoi ça marche
La ROC compte les fausses alertes par rapport aux bénignes : le FPR, c’est le nombre de fausses alertes divisé par 357. Le rappel compte les bonnes détections par rapport aux malignes. Quand vous retirez des malignes au hasard, les deux fractions restent à peu près les mêmes, donc la courbe ROC et son aire bougent à peine. Au seuil 0,3, le modèle lance une alerte pour 144 bénignes sur 357 (FPR 40,3 %), qu’il y ait 212 malignes ou 19.
La précision compte les fausses alertes par rapport à toutes les alertes. Avec 212 malignes et le seuil 0,3, le modèle en trouve 177, donc la précision vaut 55,1 %. Avec 19 malignes, il en trouve 17, et les 144 fausses alertes restent : la précision tombe à 10,6 %, soit 8,5 fausses alertes pour une juste. La courbe PR tombe avec la précision, et l’AP passe de 0,591 à 0,137 en moyenne. La ligne du hasard sur la PR descend aussi, jusqu’à la part de malignes : 0,051.
Ce n’est pas la chance d’un tirage ni d’un découpage en parties. Avec 40 malignes (10 %), le ROC AUC vaut 0,773 en moyenne et l’AP 0,232. Dans le code ci-dessous, le même modèle sur 20 autres découpages a, avec 19 malignes, un AP inférieur à la moitié de celui obtenu avec toutes les données, à chaque fois.
Erreur fréquente
Vrai ou faux : « un ROC AUC élevé signifie peu de fausses alertes ». Faux. Le ROC AUC mesure à quel point le modèle trie bien : la probabilité qu’une biopsie maligne prise au hasard reçoive un score plus élevé qu’une bénigne prise au hasard. Il ne dit pas combien d’alertes seront fausses, car cela dépend de la rareté de la classe. Dans le lab, avec 19 malignes, le ROC AUC vaut 0,772 en moyenne, presque autant qu’avec 212, et au seuil 0,3 il y a 8,5 fausses alertes pour une juste. Quand la classe est rare, regardez la courbe PR et la précision au seuil que vous utiliserez vraiment.
Un avertissement dans l’autre sens : l’AP n’est pas non plus un nombre « sur le modèle seul ». Il dépend de la part de la classe dans les données, donc les AP de deux jeux aux proportions différentes ne se comparent pas directement. Comparez l’AP à la ligne du hasard sur les mêmes données.
Quiz
Trois questions pour vérifier vos acquis. Choisissez une réponse ou dépliez la solution sous chaque question. Au clavier : les flèches choisissent, Entrée ou Espace valide.
À retenir
- La courbe ROC et la courbe PR montrent tous les seuils à la fois ; le seuil se choisit ensuite, selon le coût des erreurs.
- Le ROC AUC mesure à quel point le modèle trie bien et dépend à peine des proportions des classes.
- Quand la classe positive est rare, les mêmes fausses alertes mangent la précision : regardez la courbe PR et l’AP.
- Comparez l’AP à la ligne du hasard, la part de la classe positive dans les mêmes données.
Pour aller plus loin : formule, code, pratique
Les maths
Au seuil t, le modèle dit « maligne » quand son score s ≥ t. Alors rappel = TP / (TP + FN), FPR = FP / (FP + TN), précision = TP / (TP + FP).
Le FPR n’a que des bénignes au dénominateur, le rappel que des malignes. Si vous retirez des malignes au hasard, aucune des deux fractions ne change de façon systématique, donc la courbe ROC reste. La précision a les deux sortes d’alertes au dénominateur. Au seuil 0,3 : 177 / (177 + 144) ≈ 0,551 avec 212 malignes et 17 / (17 + 144) ≈ 0,106 avec 19.
Le ROC AUC est la probabilité qu’une maligne prise au hasard reçoive un score plus élevé qu’une bénigne prise au hasard : AUC = P(s₊ > s₋), les égalités comptant pour moitié. L’AP est la précision moyenne pondérée par les sauts de rappel : AP = Σₖ (Rₖ − Rₖ₋₁) · Pₖ. Des scores au hasard donnent un AUC de 0,5 et un AP égal à la part de la classe positive : 212 / 569 ≈ 0,373 ou 19 / 376 ≈ 0,051.
En code (Python)
La même expérience dans scikit-learn : scores de validation croisée, ROC AUC et AP avec 212, 40 et 19 malignes (moyennes sur 1000 tirages), puis la même chose sur 20 autres découpages.
import numpy as np
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import StratifiedKFold, cross_val_predict
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import roc_auc_score, average_precision_score
X, y = load_breast_cancer(return_X_y=True)
X, y = X[:, [1]], 1 - y # seulement la texture moyenne, comme dans le lab ; 1 = maligne
model = make_pipeline(StandardScaler(), LogisticRegression())
def scores(cv): # scores de validation : chaque biopsie est notée par un modèle qui ne l’a jamais vue
return cross_val_predict(model, X, y, cv=cv, method="predict_proba")[:, 1]
ben, mal = np.flatnonzero(y == 0), np.flatnonzero(y == 1)
def rare(p, keep, draws, seed): # les 357 bénignes + `keep` malignes au hasard, moyenne des tirages
rng = np.random.default_rng(seed)
rows = [np.r_[ben, rng.choice(mal, keep, replace=False)] for _ in range(draws)]
return np.mean([(roc_auc_score(y[i], p[i]), average_precision_score(y[i], p[i])) for i in rows], axis=0)
p = scores(StratifiedKFold(5))
print(f"212 malignant ({212 / 569:.0%}): ROC AUC {roc_auc_score(y, p):.3f}, AP {average_precision_score(y, p):.3f}")
for keep in (40, 19):
auc, ap = rare(p, keep, 1000, 0)
print(f"{keep} malignant ({keep / (357 + keep):.0%}), mean of 1000 draws: ROC AUC {auc:.3f}, AP {ap:.3f}")
r = []
for s in range(20): # 20 autres façons de couper les données en 5 parties
q = scores(StratifiedKFold(5, shuffle=True, random_state=s))
r.append([roc_auc_score(y, q), average_precision_score(y, q), *rare(q, 19, 200, s)])
r = np.array(r)
print(f"20 other fold splits, 212 -> 19 malignant: ROC AUC {r[:, 0].mean():.3f} -> {r[:, 2].mean():.3f}, AP {r[:, 1].mean():.3f} -> {r[:, 3].mean():.3f}; AP below half in {(r[:, 3] < r[:, 1] / 2).sum()} of 20")
Sortie
212 malignant (37%): ROC AUC 0.773, AP 0.591
40 malignant (10%), mean of 1000 draws: ROC AUC 0.773, AP 0.231
19 malignant (5%), mean of 1000 draws: ROC AUC 0.774, AP 0.140
20 other fold splits, 212 -> 19 malignant: ROC AUC 0.774 -> 0.775, AP 0.595 -> 0.140; AP below half in 20 of 20
Avec toutes les malignes, les nombres sont les mêmes que dans le lab. Avec 40 et 19, le code tire les malignes autrement que le lab et fait 1000 tirages au lieu de 200 ; les moyennes diffèrent donc à la troisième décimale : AP 0,140 au lieu de 0,137. Sur 20 autres découpages, le tableau est le même : le ROC AUC reste, et l’AP tombe sous la moitié à chaque fois.
Télécharger le notebook (.ipynb). Ouvrez-le dans Jupyter ou importez-le dans Google Colab ; il télécharge lui-même les données manquantes.
Pour les praticiens
- Dans scikit-learn, les nombres viennent de
roc_auc_scoreetaverage_precision_score, etRocCurveDisplayetPrecisionRecallDisplaytracent les courbes. Calculez-les sur des scores de validation (cross_val_predict(..., method="predict_proba")), pas sur les données d’apprentissage. - Avec une classe rare (fraudes, maladies rares, pannes), donnez l’AP à côté du ROC AUC, et à côté de l’AP la ligne du hasard, c’est-à-dire la part de la classe positive.
- Une courbe est un menu de seuils. Choisissez le seuil en validation selon le coût des erreurs, par exemple « rappel d’au moins 90 % avec la meilleure précision possible », et vérifiez-le ensuite seulement sur le test.
- Le ROC AUC de deux jeux aux proportions différentes se compare, mais il ne dit pas combien d’alertes seront fausses ; l’AP en dit plus, mais comparez-le seulement à proportions égales.
Cela vous a-t-il aidé ?
Merci ! Cela nous aide à nous améliorer.
Aller plus loin dans l’Atlas
Articles de l’encyclopédie sur les notions de cette leçon :