Le machine learning en partant de zéro · Leçon 2.6 · 13 sur 33 leçons prêtes · 12 min
Métrique et seuil selon le coût des erreurs
En bref
On choisit le seuil selon le prix des erreurs, pas par habitude. Si un oubli coûte 10 fois plus qu’une fausse alerte, le seuil le moins cher est près de 0,09.
Échauffement Deux questions de leçons précédentes. Une minute, sans jamais bloquer la leçon.
Dans la leçon 2.3, les courbes ont montré un menu de seuils, et dans la leçon 2.4 vous avez vérifié quand les nombres d’un modèle sont de vrais pourcentages. Vous allez maintenant choisir un seuil dans ce menu. Pas par habitude (0,5), ni pour une métrique favorite, mais selon ce que coûte vraiment chaque erreur.
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 : Plus près de 0,1, car une alerte est rentable dès un risque faible
Théorie de la décision : une alerte est rentable quand p · 10 > (1 − p) · 1, c’est-à-dire p > 1/11 ≈ 0,09. Dans le lab, le seuil 0,09 coûte 125 et le 0,5 habituel jusqu’à 254. Le seuil le moins cher sur la validation, 0,06, coûte 111, mais seulement sur les mêmes scores que ceux qui ont servi à le choisir.
À vous de jouer
- Gardez les prix 10 et 1 et descendez le seuil depuis 0,5. Où le coût est-il le plus bas ? Combien d’oublis et combien de fausses alertes y a-t-il alors ?
- Mettez les deux coûts à 1. Où est maintenant le seuil le moins cher ? Comparez-le au seuil du meilleur F1.
- Rendez une fausse alerte plus chère qu’un oubli. De quel côté de 0,5 tombe le seuil le moins cher ?
- Revenez aux prix 10 et 1 et comparez trois coûts : celui du seuil le moins cher, celui de la vérification honnête et celui du seuil de la théorie. Quel choix est le moins cher sur des biopsies qui n’ont pas servi à le faire ?
Une fois vérifié dans le lab, mettons un nom sur ce que vous voyez.
L’idée en quelques mots
Chaque erreur a un prix. Une tumeur maligne manquée (FN), c’est une maladie découverte trop tard. Une fausse alerte (FP), c’est une biopsie inutile et du stress. Quand on connaît les prix, le coût d’un seuil est une simple somme : les oublis fois le prix d’un oubli, plus les fausses alertes fois le prix d’une alerte. Le meilleur seuil est celui dont la somme est la plus petite sur les données de validation.
Avec les prix 10 et 1, le seuil 0,5 donne 24 oublis et 14 fausses alertes, soit un coût de 254. Le seuil le moins cher sur la validation est 0,06 : 2 oublis et 91 alertes, coût 111. Ce nombre est pourtant optimiste, car le seuil a été choisi et évalué sur les mêmes scores (plus de détails dans « Pourquoi ça marche »). Pour comparer, une biopsie pour toutes coûte 357, et aucune biopsie 2120.
Si le modèle est calibré, on peut aussi calculer le seuil sans le chercher. Une biopsie a une probabilité de malignité p. Une alerte coûte alors en moyenne (1 − p) · 1, et pas d’alerte p · 10. L’alerte est rentable quand p · 10 > (1 − p) · 1, c’est-à-dire quand p > 1/11 ≈ 0,09. En général, le seuil vaut c_FP / (c_FP + c_FN). C’est un résultat de la théorie de la décision, pas une mesure : il suppose que les nombres du modèle sont de vrais pourcentages (leçon 2.4). Ce modèle est bien calibré (ECE 0,010). Dans le lab, le seuil 0,09 coûte 125, moins de la moitié du coût du seuil 0,5, et personne ne l’a réglé sur ces données.
Jak to policzono
- Biopsies : Breast Cancer Wisconsin (Diagnostic), UCI, licence CC BY 4.0. 569 biopsies (212 malignes, 357 bénignes), 10 mesures « mean » chacune.
- Scores de 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. - Modèle : standardisation et régression logistique (C = 1). Seuils de 0,01 à 0,99 par pas de 0,01.
- Prix des erreurs : un oubli 10, une fausse alerte 1. C’est un exemple, pas une évaluation médicale.
Pourquoi ça marche
Le lab et la théorie sont presque d’accord : le seuil le moins cher vaut 0,06, la théorie dit 0,09. L’écart vient de ce que 569 biopsies, c’est peu, alors qu’un oubli pèse autant que 10 alertes : la courbe de coût fait des sauts. Son fond est plat et dentelé : le seuil 0,13 coûte autant que 0,06 (111), et 0,09 coûte 125. Sur 20 autres découpages en parties (code ci-dessous), le seuil le moins cher tombe entre 0,04 et 0,13, en moyenne 0,08. La théorie vise le milieu de cet intervalle, et le lab montre à quel point le fond est large.
Le seuil le moins cher cache pourtant un piège. Le lab essaie 99 seuils et garde celui qui a le mieux réussi sur ces 569 biopsies, en partie grâce à des coups de chance. Le coût 111 est donc optimiste : c’est la même malédiction du gagnant que lors du réglage (leçon 3.5). Une vérification honnête : choisissez le seuil sur 4/5 des biopsies et calculez son coût sur le 1/5 restant, cinq fois. Choisi ainsi, le seuil coûte 141, plus que le seuil de la théorie 0,09 (125), que personne n’a réglé. Sur 20 autres découpages, le coût honnête du seuil choisi va de 106 à 153 (129 en moyenne), tandis que le seuil de la théorie coûte de 105 à 136 (117 en moyenne) et est moins cher dans 16 cas sur 20. Conclusion : avec un modèle calibré, le seuil de la théorie est un point de départ solide et peu coûteux, et régler le seuil sur les mêmes données exagère l’économie.
Le sens est toujours le même : plus l’oubli est cher, plus le seuil est bas, et plus la fausse alerte est chère, plus il est haut. À prix égaux, le seuil le moins cher est 0,65 (coût 33). Quand une alerte coûte plus qu’un oubli, le seuil le moins cher passe au-dessus de 0,5.
Erreur fréquente
Vrai ou faux : « le F1 est une bonne métrique pour tout ». Faux. F1 = 2·TP / (2·TP + FN + FP), donc le F1 pèse un oubli et une fausse alerte de la même façon, même quand leurs prix diffèrent. Dans le lab, le seuil du meilleur F1 est 0,65 (F1 0,918). Aux prix 10 et 1, il coûte 276 : plus que le 0,5 habituel (254) et presque 2,5 fois le seuil le moins cher (111). Sur 20 autres découpages, le seuil du meilleur F1 coûte de 1,6 à 2,9 fois le moins cher.
Même à prix égaux, le F1 n’est pas la même chose que le coût. Dans le lab, aux prix 1 et 1, le seuil le moins cher tombe justement là où le F1 est le meilleur (0,65), mais ce n’est pas une règle. Le coût à prix égaux, c’est simplement le nombre d’erreurs, alors que le F1 est une fraction où les « non » corrects (TN) ne comptent pas du tout. Sur 20 autres découpages, les deux seuils diffèrent dans 3 cas.
Si vous connaissez les prix des erreurs, calculez le coût. Sinon, demandez-les avant de choisir une métrique : choisir une métrique, c’est aussi décider de prix, simplement sans le dire.
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
- On choisit le seuil selon les prix des erreurs : le coût, ce sont les oublis fois leur prix plus les fausses alertes fois le leur, calculé sur la validation.
- Pour un modèle calibré, la théorie donne le seuil c_FP / (c_FP + c_FN) ; aux prix 10 et 1, environ 0,09. C’est un point de départ solide : un seuil réglé sur les mêmes données paraît moins cher qu’il ne l’est.
- Des oublis plus chers abaissent le seuil, des fausses alertes plus chères le relèvent.
- Le F1 pèse les deux erreurs de la même façon et ignore les « non » corrects ; si vous connaissez les prix, calculez le coût.
Pour aller plus loin : formule, code, pratique
Les maths
Coût d’un seuil t : K(t) = c_FN · FN(t) + c_FP · FP(t). Le seuil le moins cher sur la validation est t = argmin K(t). Son coût K(t) calculé sur les mêmes données est optimiste ; le coût honnête se calcule sur des données qui n’ont pas servi à choisir t*.
Une biopsie a une probabilité de malignité p. Une alerte coûte en moyenne (1 − p) · c_FP, pas d’alerte p · c_FN. L’alerte est rentable quand p · c_FN > (1 − p) · c_FP, c’est-à-dire p > c_FP / (c_FP + c_FN). Pour c_FN = 10 et c_FP = 1, cela donne 1 / 11 ≈ 0,09.
F1 = 2·TP / (2·TP + FN + FP) : FN et FP ont le même poids 1 au dénominateur.
En code (Python)
La même expérience dans scikit-learn : scores de validation croisée, coût de chaque seuil de 0,01 à 0,99, coût honnête du seuil choisi, puis la même chose sur 20 autres découpages en parties.
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 f1_score
X, y = load_breast_cancer(return_X_y=True)
X, y = X[:, :10], 1 - y # les 10 mesures « mean », comme dans le lab ; 1 = maligne
model = make_pipeline(StandardScaler(), LogisticRegression())
t = np.arange(1, 100) / 100 # seuils 0.01 ... 0.99, comme dans le lab
def costs(p, i=slice(None), c_fn=10, c_fp=1): # un oubli coûte 10, une fausse alerte 1; i = quelles biopsies
return np.array([c_fn * ((p[i] < s) & (y[i] == 1)).sum() + c_fp * ((p[i] >= s) & (y[i] == 0)).sum() for s in t])
def scores(cv): # chaque biopsie 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]
def held_out(p, cv): # seuil le moins cher choisi sur 4/5 des biopsies, coût sur le 1/5 restant, cinq fois
return sum(costs(p, b)[costs(p, a).argmin()] for a, b in cv.split(X, y))
p = scores(StratifiedKFold(5))
c, f1 = costs(p), np.array([f1_score(y, p >= s) for s in t])
print(f"cheapest threshold {t[c.argmin()]:.2f} (cost {c.min()}); theory 1/11 = {1 / 11:.2f} (cost {c[8]}); 0.5 costs {c[49]}; best F1 at {t[f1.argmax()]:.2f} costs {c[f1.argmax()]}")
print(f"picked on 4/5, priced on the other 1/5: {held_out(p, StratifiedKFold(5))}; theory 1/11: {c[8]}")
r = []
for s in range(20): # 20 autres découpages en 5 parties
cv = StratifiedKFold(5, shuffle=True, random_state=s)
q = scores(cv)
cq, fq = costs(q), np.array([f1_score(y, q >= u) for u in t])
r.append((t[cq.argmin()], cq[fq.argmax()] / cq.min(), cq[49] / cq.min(), held_out(q, cv), cq[8], costs(q, c_fn=1).argmin() != fq.argmax()))
r = np.array(r)
print(f"20 other cuts: cheapest threshold {r[:, 0].min():.2f} to {r[:, 0].max():.2f} (mean {r[:, 0].mean():.2f}); best F1 costs {r[:, 1].min():.1f} to {r[:, 1].max():.1f} times the cheapest, 0.5 costs {r[:, 2].min():.1f} to {r[:, 2].max():.1f} times")
print(f"20 other cuts, held out: the picked threshold costs {r[:, 3].min():.0f} to {r[:, 3].max():.0f} (mean {r[:, 3].mean():.0f}), theory 1/11 costs {r[:, 4].min():.0f} to {r[:, 4].max():.0f} (mean {r[:, 4].mean():.0f}); theory is cheaper in {(r[:, 4] < r[:, 3]).sum():.0f} of 20; at equal prices the cheapest and the best-F1 threshold differ in {r[:, 5].sum():.0f} of 20")
Sortie
cheapest threshold 0.06 (cost 111); theory 1/11 = 0.09 (cost 125); 0.5 costs 254; best F1 at 0.65 costs 276
picked on 4/5, priced on the other 1/5: 141; theory 1/11: 125
20 other cuts: cheapest threshold 0.04 to 0.13 (mean 0.08); best F1 costs 1.6 to 2.9 times the cheapest, 0.5 costs 2.0 to 2.5 times
20 other cuts, held out: the picked threshold costs 106 to 153 (mean 129), theory 1/11 costs 105 to 136 (mean 117); theory is cheaper in 16 of 20; at equal prices the cheapest and the best-F1 threshold differ in 3 of 20
Avec le découpage StratifiedKFold(5), les nombres sont ceux du lab : seuil le moins cher 0,06 (coût 111), théorie 0,09 (125), le seuil 0,5 coûte 254 et celui du meilleur F1 276. Sur 20 autres découpages, le seuil le moins cher tombe entre 0,04 et 0,13, en moyenne 0,08, et le 0,5 habituel coûte de 2,0 à 2,5 fois le moins cher. Le seuil choisi sur 4/5 des biopsies et évalué sur le 1/5 restant coûte 141, comme dans le lab. Sur 20 autres découpages, un tel choix coûte de 106 à 153 (129 en moyenne), le seuil de la théorie de 105 à 136 (117 en moyenne), et la théorie est moins chère dans 16 cas sur 20. À prix égaux, le seuil le moins cher et celui du meilleur F1 diffèrent dans 3 découpages sur 20.
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
- Fixez les prix des erreurs avec les personnes qui en subissent les conséquences (une médecin, une équipe risques) avant de voir les résultats du modèle. Sinon, il est facile de choisir des prix qui arrangent un seuil qui vous plaît déjà.
- Dans scikit-learn,
TunedThresholdClassifierCVavec votre proprescoring(par exemple viamake_scorer) règle le seuil sur un coût. On applique un seuil soi-même ainsi :predict_proba(X)[:, 1] >= t. - Réglez le seuil sur la validation et vérifiez son coût sur des données qui n’ont pas servi à le choisir (le test, ou une partie mise de côté comme dans le lab). Donnez le coût à côté de deux repères simples : « toutes en biopsie » et « aucune ».
- N’utilisez la formule c_FP / (c_FP + c_FN) que pour un modèle calibré (leçon 2.4). Si le modèle est trop sûr de lui, cherchez le seuil sur la courbe de coût.
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 :