ML Atlas

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.
De la leçon 2.2 : Évaluer un classifieur : au-delà de l’exactitude Un modèle de dépistage manque beaucoup de cancers mais ne déclenche presque jamais de fausse alerte. Quel nombre est bas ?

Voir la réponse

Bonne réponse : Le rappel, soit la part de cancers détectés

Le rappel est la part des vrais positifs qui ont été détectés, donc beaucoup d’oublis signifient un rappel bas.

De la leçon 2.1 : Classification : tracer une frontière Vous montez le seuil de 0,5 à 0,8. Qu’arrive-t-il à la frontière ?

Voir la réponse

Bonne réponse : Elle se translate sans pivoter : moins de manchots sont classés dans l’espèce B

Chaque seuil correspond à une droite de même direction ; un seuil plus strict la décale pour que seuls les cas assurés passent.

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.

Prédisez, puis vérifiez Le même modèle note les mêmes 357 biopsies bénignes. D’abord il y a 212 malignes (37 % des données), puis seulement 19 (5 %). Que devient le ROC AUC (l’aire sous la courbe ROC), et que devient l’AP, l’aire sous la courbe PR ?
Quel est votre degré de certitude ?

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.

1. Que montre la courbe ROC ?
Voir la réponse

Bonne réponse : Le rappel en fonction de la part de fausses alertes, pour tous les seuils

Chaque point de la courbe est un seuil. Un seuil élevé, c’est le coin inférieur gauche ; un seuil bas, le coin supérieur droit. L’aire sous la courbe, le ROC AUC, résume tous les seuils en un nombre : ici 0,773.

2. Les malignes font 5 % au lieu de 37 %. Le ROC AUC bouge à peine. Pourquoi l’AP chute-t-il ?
Voir la réponse

Bonne réponse : Parce que les mêmes fausses alertes forment une bien plus grande part des alertes

Le FPR divise les fausses alertes par le nombre de bénignes, qui ne change pas. La précision les divise par toutes les alertes. Au seuil 0,3 avec 19 malignes, il y a 144 fausses alertes pour 17 justes.

3. Quand la courbe PR en dit-elle plus que la courbe ROC ?
Voir la réponse

Bonne réponse : Quand la classe positive est rare et que compte la part d’alertes justes

Avec une classe rare, la courbe ROC a la même allure alors que la précision chute. Dans le lab avec 19 malignes, l’AP tombe à 0,137 en moyenne alors que le ROC AUC bouge à peine.

À 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.

Pour les praticiens
  • Dans scikit-learn, les nombres viennent de roc_auc_score et average_precision_score, et RocCurveDisplay et PrecisionRecallDisplay tracent 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.

Aller plus loin dans l’Atlas

Articles de l’encyclopédie sur les notions de cette leçon :