Quatre-vingt-seize pour cent, et inutile
Un filtre à spam est testé sur 1000 messages. Il a juste 960 fois, donc il fait 96 pour cent. L’équipe est contente.
Puis quelqu’un découvre que le filtre répond « pas du spam » à tous les messages, sans exception. Quarante messages sur 1000 étaient pourtant du spam. Un seul score a caché toute la faute.
À la fin de cette leçon
Remarque
Je peux juger un classeur avec une matrice de confusion, la précision et le rappel, et pas seulement avec l’exactitude.
Mots clés
| Mot | Ce que ça veut dire |
|---|---|
| Exactitude | la part de tous les messages que le modèle a bien classés |
| Déséquilibré | une étiquette est bien plus fréquente que l’autre |
| Matrice de confusion | un tableau des bonnes et des mauvaises réponses pour chaque étiquette |
| Précision | parmi les messages signalés, la part qui était vraiment du spam |
| Rappel | parmi les vrais spams, la part qui a été signalée |
| Seuil | le score à partir duquel un message est signalé |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
L’exactitude : un nombre pour deux erreurs
L’exactitude compte toutes les bonnes réponses de la même façon. Cela convient quand les étiquettes sont à peu près aussi fréquentes.
Cela échoue quand le tableau est déséquilibré. Si 40 messages sur 1000 sont du spam, un modèle qui ne dit jamais « spam » a juste 960 fois. Il a juste 96 pour cent du temps et ne trouve aucun spam.
Noter un modèle qui ne dit jamais spam
docker exec jupyter python3 -c "t=[1]*40+[0]*960; g=[0]*1000; print(sum(a==b for a,b in zip(t,g))/1000)"Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Compter les quatre sortes de réponse
Le spam est ce que l’on cherche : appelez-le positif. Chaque message tombe dans l’une de quatre cases.
Attrapé : spam, signalé. Fausse alerte : pas du spam, signalé. Manqué : spam, pas signalé. Rejet juste : pas du spam, pas signalé. Les quatre comptes forment la matrice de confusion.
Exemple travaillé : un filtre sur 1000 messages
| Signalés comme spam | Pas signalés | |
|---|---|---|
| Vraiment du spam (40) | Attrapés : 30 | Manqués : 10 |
| Pas du spam (960) | Fausses alertes : 20 | Rejets justes : 940 |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Afficher la matrice, la précision et le rappel
docker exec jupyter python3 -c "from sklearn.metrics import confusion_matrix, precision_score, recall_score; t=[1]*40+[0]*960; g=[1]*30+[0]*10+[1]*20+[0]*940; print(confusion_matrix(t,g)); print(round(precision_score(t,g),3), round(recall_score(t,g),3), (30+940)/1000)"Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
La précision et le rappel posent deux questions
La précision demande : quand le filtre dit spam, a-t-il souvent raison ? Ici, 30 messages sur les 50 signalés, soit 0.6.
Le rappel demande : parmi les vrais spams, combien le filtre en a-t-il trouvé ? Ici, 30 sur 40, soit 0.75. L’exactitude était de 0.97. Le filtre vaut mieux que celui qui ne dit jamais spam, mais l’exactitude montre à peine de combien.
Bouger le seuil échange l’un contre l’autre
La plupart des modèles donnent un score, et un seuil le transforme en étiquette. Baissez le seuil et plus de messages sont signalés. On attrape plus de spam, mais on signale aussi plus de bons messages.
La précision et le rappel tirent donc en sens contraire, et une personne doit choisir. Lancez le code et regardez bouger les comptes.
Quatre seuils sur dix messages
# Dix messages : le score donné par un modèle (de 0 à 1) et le message était-il du spam.
messages = [
(0.95, 1), (0.9, 1), (0.8, 0), (0.7, 1), (0.6, 0),
(0.5, 1), (0.4, 0), (0.3, 0), (0.2, 0), (0.1, 0),
]
for seuil in [0.9, 0.7, 0.5, 0.3]:
attrapes = 0
fausses_alertes = 0
manques = 0
for score, spam in messages:
signale = score >= seuil
if signale and spam == 1:
attrapes = attrapes + 1
if signale and spam == 0:
fausses_alertes = fausses_alertes + 1
if not signale and spam == 1:
manques = manques + 1
print("seuil", seuil, "attrapés", attrapes, "fausses alertes", fausses_alertes, "manqués", manques)
# Quel seuil choisiriez-vous pour une boîte mail ? Et pour une banque ?
Exemple travaillé : ce que donne chaque seuil
| Seuil | Attrapés | Fausses alertes | Manqués | Précision | Rappel |
|---|---|---|---|---|---|
| 0.9 | 2 | 0 | 2 | 1.0 | 0.5 |
| 0.7 | 3 | 1 | 1 | 0.75 | 0.75 |
| 0.5 | 4 | 2 | 0 | 0.667 | 1.0 |
| 0.3 | 4 | 4 | 0 | 0.5 | 1.0 |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Une erreur fréquente
Attention
Beaucoup pensent qu’il existe un meilleur seuil, le même pour tous. Il n’y en a pas tant que l’on ne connaît pas le coût de chaque erreur. Une boîte mail peut vivre avec un peu de spam. Un contrôle de fraude ne peut pas en laisser passer.
Plus loin : le coût de chaque erreur
Admettons qu’un spam manqué coûte 1 minute de lecture et qu’une fausse alerte coûte 5 minutes de recherche d’un message perdu. Reprenez le tableau des quatre seuils.
Calculez les minutes perdues à chaque seuil. Quel seuil coûte le moins ? Cela changerait-il si une fausse alerte ne coûtait qu’1 minute ?