Module 9 — Surveillance : dérive des données et du concept
Le service tourne. Les tests passent. La latence est bonne. Trois mois plus tard, l'AUC réelle est passée de 0,84 à 0,71 sans qu'aucune alerte ne se déclenche. Le modèle n'a pas planté, il s'est dégradé. Ce module met en place les mesures qui rendent visible cette dégradation silencieuse.
Quatre choses à surveiller, pas seulement le modèle
Un service de prédiction produit quatre familles de signaux qu'il faut traiter comme un tout.
- Signaux applicatifs : latence médiane, latence p95, taux d'erreur HTTP, utilisation CPU. Ce sont les métriques classiques d'un service web ; elles ne parlent pas du modèle mais leur absence disqualifie toute autre mesure.
- Signaux de dérive des données : la distribution des variables en entrée a-t-elle changé par rapport à celle du jeu d'entraînement ?
- Signaux de dérive du concept : la relation entre les entrées et la cible a-t-elle changé ? Autrement dit, une même entrée mène-t-elle encore à la même sortie qu'il y a trois mois ?
- Signaux de performance directe : quand la vérité terrain arrive (l'abonné a-t-il vraiment résilié dans les 30 jours ?), la performance peut être recalculée à froid et comparée à celle attendue.
Tester la dérive d'une variable numérique
Le test de Kolmogorov-Smirnov compare la distribution récente d'une variable à la distribution de référence :
from scipy.stats import ks_2samp
import pandas as pd
def derive_ks(reference: pd.Series, recent: pd.Series, seuil: float = 0.05) -> bool:
stat, p_valeur = ks_2samp(reference.dropna(), recent.dropna())
return p_valeur < seuil # True si la difference est significative
Pour une variable catégorielle, on compare deux tables de fréquence par un test du chi-carré. Pour un modèle avec 400 variables, on ne surveille pas les 400 : on surveille les 30 les plus importantes selon l'importance attribuée par le modèle, plus les variables métier connues pour être sensibles.
L'indicateur PSI, plus lisible pour les métiers
Le Population Stability Index compare deux distributions par tranches :
import numpy as np
def psi(reference: np.ndarray, recent: np.ndarray, nb_tranches: int = 10) -> float:
bornes = np.quantile(reference, np.linspace(0, 1, nb_tranches + 1))
bornes[0], bornes[-1] = -np.inf, np.inf
p_ref, _ = np.histogram(reference, bins=bornes, density=False)
p_rec, _ = np.histogram(recent, bins=bornes, density=False)
p_ref = np.clip(p_ref / p_ref.sum(), 1e-6, None)
p_rec = np.clip(p_rec / p_rec.sum(), 1e-6, None)
return float(((p_rec - p_ref) * np.log(p_rec / p_ref)).sum())
L'usage établi :
PSI < 0.10: population stable.0.10 <= PSI < 0.25: dérive modérée, à investiguer.PSI >= 0.25: dérive nette, action requise.
PSI est plus grossier que le test KS mais il produit un nombre unique
qu'un cadre non technique peut suivre dans le temps.
Dérive du concept : la plus dangereuse
La dérive des données est visible aux entrées. La dérive du concept ne l'est pas : les variables gardent la même distribution, mais leur lien avec la cible a changé. Un exemple : un opérateur télécom lance un programme de fidélité en mars ; les abonnés qui avaient un profil de résiliation ne résilient plus. Le modèle continue de les signaler à haut risque, la vérité ne suit plus.
Deux mesures rendent cette dérive détectable.
- Un rapport hebdomadaire de l'AUC recalculée dès que la vérité terrain arrive. Un décrochage soudain trahit une dérive du concept.
- Une comparaison entre l'AUC réelle et l'AUC prédite par le calibrage du modèle. Un modèle qui prédit 20 % de résiliation en moyenne alors que la réalité en donne 8 % est passé à côté d'un changement de fond.
Un rapport Evidently, en une commande
from evidently.report import Report
from evidently.metric_preset import DataDriftPreset, TargetDriftPreset
rapport = Report(metrics=[DataDriftPreset(), TargetDriftPreset()])
rapport.run(reference_data=reference, current_data=recent)
rapport.save_html("rapports/derive_semaine_36.html")
Evidently produit un rapport HTML lisible qui met côte à côte les
distributions, calcule les tests, et signale les variables déviantes. Ce
rapport est envoyé chaque lundi à l'équipe métier ; il ouvre une
conversation là où un nombre seul en fermait une.
L'alerte utile contre l'alerte bruyante
Une alerte qui se déclenche tous les jours est ignorée en une semaine. Trois principes séparent une alerte utile d'une alerte bruyante.
Ne pas alerter sur la variabilité normale. Un test KS sur des
échantillons petits déclenche en permanence. On alerte à partir d'un
échantillon d'au moins quelques milliers d'observations récentes, et
sur la moyenne mobile d'un PSI, pas sur le PSI du jour.
Un seuil qui a du sens métier. Le PSI à 0,25 est un chiffre
consensuel, pas une règle physique. Pour un modèle stable, on peut serrer
à 0,20 ; pour un modèle sur un domaine mouvant, ouvrir à 0,35. Fixer un
seuil sans avoir mesuré la ligne de base est le premier générateur
d'alertes fausses.
Une action attachée. Chaque alerte pointe vers une consigne écrite : qui investigue, en combien de temps, quelle décision peut être prise sans réunion. Une alerte sans action est un bruit d'ambiance.
Un test statistique sur des milliers de variables trouve toujours des « dérives » significatives par pure chance. Sans correction pour tests multiples (Bonferroni ou FDR de Benjamini-Hochberg), 5 % des variables seront signalées comme dérivant chaque jour, alors même que rien n'a changé. Une équipe qui reçoit 20 alertes par jour arrête de les lire, et la vraie alerte du mardi suivant se perd.
En résumé
- Surveillez quatre familles : latence et erreurs applicatives, dérive des données, dérive du concept, performance directe quand la vérité arrive.
- KS pour les variables numériques, chi-carré pour les catégorielles,
PSIpour un chiffre unique lisible par le métier. - La dérive du concept est invisible aux entrées ; elle exige la vérité terrain, même en différé.
- Une alerte doit avoir un seuil métier, une taille d'échantillon minimale et une action attachée ; sans ces trois, elle est du bruit.
Le module 10 boucle la boucle : quand la dérive dépasse un seuil, on déclenche un réentraînement, on valide la nouvelle version, on la promeut ou on retombe sur l'ancienne.