Un score trop beau
Une fuite de données arrive quand un modèle voit, avant le test, une information qui devait lui rester cachée. Elle gonfle le score sans rendre le modèle meilleur.
Une équipe teste un modèle sur des lignes gardées de côté. On lui dit qu’il a juste neuf fois sur dix. À l’usage, il a juste sept fois sur dix.
Le modèle n’avait rien de faux. Les lignes du test n’étaient pas vraiment nouvelles. Quand un score paraît trop beau, demandez d’abord ce que le modèle a peut-être déjà vu.
À la fin de cette leçon
Remarque
Je peux garder un jeu de test propre et repérer quand de l’information y a fui.
Mots-clés
| Mot | Ce que ça veut dire |
|---|---|
| Jeu de test | des lignes gardées de côté, regardées une seule fois, à la toute fin |
| Jeu de validation | des lignes qui servent à choisir entre des modèles et des réglages |
| Fuite | de l’information du test, ou de la réponse, qui atteint le modèle avant le test |
| Doublon | une ligne qui apparaît plusieurs fois |
| Référence | le score d’une devinette très simple, pour comparer |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Trois jeux, trois rôles
À la leçon précédente, vous avez gardé un jeu de validation. Vous l’avez regardé souvent, pour décider quand arrêter et quels réglages prendre.
Il devient donc un peu moins neuf à chaque fois. Une équipe prudente garde un troisième jeu, le jeu de test. On l’utilise une seule fois, à la fin, pour le score que l’on annonce.
Exemple travaillé : une année en trois jeux
| Jeu | Part | Jours | Sert à |
|---|---|---|---|
| Jeu d’entraînement | 60 pour cent | 219 | Régler les poids |
| Jeu de validation | 20 pour cent | 73 | Choisir un modèle et ses réglages |
| Jeu de test | 20 pour cent | 73 | Le seul score honnête, à la fin |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Calculer les trois tailles
docker exec jupyter python3 -c "print(int(365 * 0.6), int(365 * 0.2), 365 - int(365 * 0.6) - int(365 * 0.2))"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 fuite : le test n’est pas vraiment neuf
Une fuite est toute façon dont le modèle voit de l’information du test avant le test. La plus simple est un doublon : la même ligne dans le jeu d’entraînement et dans le jeu de test.
Un modèle qui ne fait que retenir des lignes paraît alors excellent. Lancez le code et regardez-le arriver avec un modèle qui ne fait que retenir.
Un modèle qui ne fait que retenir
# Huit jours : (température, pluie) et le jour était chargé ou calme.
jours = [
((3, 0), "calme"), ((8, 0), "charge"), ((12, 2), "calme"), ((15, 0), "charge"),
((18, 0), "charge"), ((9, 5), "calme"), ((21, 0), "charge"), ((6, 3), "calme"),
]
entrainement = jours[:6]
nouveaux = jours[6:]
copies = jours[:2] + jours[6:]
def memoriseur(jour):
# Retient chaque jour d’entraînement tel quel. Un jour inconnu reçoit "calme".
for connu, etiquette in entrainement:
if connu == jour:
return etiquette
return "calme"
def score(lignes):
justes = 0
for jour, etiquette in lignes:
if memoriseur(jour) == etiquette:
justes = justes + 1
return justes / len(lignes)
print("sur ses jours d’entraînement :", score(entrainement))
print("sur deux jours nouveaux :", score(nouveaux))
print("sur deux copies et deux jours nouveaux :", score(copies))
# Quel score croiriez-vous ? Changez un jour nouveau et relancez.
Le même test sur un vrai tableau
Voici la même idée sur les locations de vélos du labo. Un modèle du plus proche voisin répond avec l’étiquette du jour connu le plus proche : il ressemble à un mémoriseur. Un jour chargé compte 300 locations ou plus.
Écrivez d’abord un petit script dans le labo. Il prend un mot : honnete, doubles ou reponse.
Écrire le script dans le labo
docker exec jupyter sh -c "printf '%s\n' 'import sys' 'import pandas as pd' 'from sklearn.model_selection import train_test_split' 'from sklearn.neighbors import KNeighborsClassifier' '' 'hires = pd.read_csv(\"hires.csv\")' 'facon = sys.argv[1]' 'if facon == \"doubles\":' ' hires = pd.concat([hires, hires], ignore_index=True)' 'colonnes = [\"temp_c\", \"rain_mm\"]' 'if facon == \"reponse\":' ' colonnes = colonnes + [\"hires\"]' 'etiquette = hires[\"hires\"] >= 300' 'X_ent, X_test, y_ent, y_test = train_test_split(hires[colonnes], etiquette, test_size=0.25, random_state=1)' 'modele = KNeighborsClassifier(n_neighbors=1).fit(X_ent, y_ent)' 'print(facon, \"appris :\", round(modele.score(X_ent, y_ent), 3), \"gardé de côté :\", round(modele.score(X_test, y_test), 3))' > steps/fuite.py"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.
Le lancer honnêtement
docker exec jupyter python3 steps/fuite.py honneteAffiché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.
Écrire chaque jour deux fois, puis couper
docker exec jupyter python3 steps/fuite.py doublesAffiché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.
Une colonne qui donne la réponse
L’autre fuite fréquente est une colonne qui contient la réponse, ou quelque chose qu’on ne sait qu’après coup. Un indicateur de remboursement dans un tableau qui prédit les remboursements en est une. Un total calculé après l’événement aussi.
Dans le labo, hires est le nombre qui sert à fabriquer l’étiquette. Mettez-le parmi les entrées et regardez.
Donner la colonne hires au modèle
docker exec jupyter python3 steps/fuite.py reponseAffiché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.
Une erreur fréquente
Attention
Beaucoup pensent qu’un score élevé prouve un bon modèle. Il peut seulement prouver que le test était facile. Un score parfait sur des lignes gardées de côté est une raison de chercher une fuite, pas de fêter.
Exemple travaillé : trois fuites et leurs contrôles
| Ce qui s’est passé | Pourquoi cela fuit | Comment vérifier |
|---|---|---|
| Chaque jour écrit deux fois, puis coupé | Une ligne de test a un jumeau dans l’entraînement | Compter les lignes de test qui sont aussi dans l’entraînement |
| La colonne hires sert à prédire une étiquette faite avec hires | L’entrée contient la réponse | Demander de chaque colonne : est-elle connue avant la réponse ? |
| Dix modèles essayés, le meilleur score de test annoncé | Le jeu de test a servi à choisir | Choisir avec la validation, tester une fois |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Plus loin : la fuite dans votre carnet
Prenez hires.csv du labo et un modèle à vous. Notez le score sur les jours appris et sur les jours gardés de côté.
Ajoutez ensuite une colonne qui, selon vous, fuit, et relancez. De combien le score bouge-t-il ? Écrivez une phrase : pourquoi cette colonne n’existerait pas le jour où vous auriez vraiment besoin d’une prédiction ?