Il y a fuite de données quand le modèle apprend à partir d’une information qui ne sera pas disponible au moment de prédire pour de vrai. Le score monte, parfois spectaculairement, et il est faux.
C’est le défaut le plus dangereux du métier, pour une raison précise : il ne produit aucune erreur. Un modèle trop simple se voit, un modèle qui surapprend se voit sur la courbe de validation. Une fuite donne un modèle qui a l’air excellent partout, jusqu’au jour où il passe en production et s’effondre.
La cible dans les variables. Une colonne qui contient la réponse, ou une conséquence de la réponse. montant_rembourse pour prédire un défaut de paiement, date_de_resiliation pour prédire l’attrition, duree_hospitalisation pour prédire une complication. Le signal est parfait parce que la colonne est écrite après l’événement.
La fuite temporelle. Une variable calculée sur toute la période, y compris après l’instant de prédiction : une moyenne de dépenses annuelle utilisée pour prédire un achat de mars, un agrégat par client calculé sur l’ensemble du fichier. Le modèle lit son propre futur.
La fuite par préparation. La plus fréquente, et la seule qui vienne du code plutôt que des données :
# Faux : la moyenne et l'écart-type sont calculés sur tout le jeu,
# donc le jeu de test a influencé la transformation.
X = StandardScaler().fit_transform(X)
X_ent, X_test = train_test_split(X)
# Juste : la transformation est apprise sur l'entraînement seul,
# puis appliquée telle quelle au test.
X_ent, X_test = train_test_split(X)
pipeline = make_pipeline(StandardScaler(), modele)
pipeline.fit(X_ent, y_ent)Cela vaut pour tout ce qui s’ajuste aux données : normalisation, imputation, sélection de variables, encodage par la cible, rééquilibrage. Tout doit vivre dans un Pipeline, et le pipeline doit être ajusté à l’intérieur de chaque bloc de validation croisée. C’est la raison d’être de cet objet, pas une élégance de style.
Trois réflexes, dans cet ordre :
Valider sur une période postérieure à celle de l’entraînement, même quand le problème n’est pas une série temporelle. Un découpage temporel reproduit la seule situation qui compte — prédire l’avenir avec le passé — et il révèle toutes les fuites temporelles d’un coup.
Et la nuance à énoncer pour finir : une fuite n’est pas toujours une erreur de code, c’est souvent une erreur de définition du problème. Prédire un défaut de paiement avec des données du service de recouvrement fonctionne parfaitement et ne sert à rien : au moment où ces données existent, la décision est déjà prise.