Module 10 — Projet : magasin pour un cas de scoring
Ce module réunit les neuf précédents dans un projet complet : partir d'un scoreur de fraude sans magasin, mesurer l'écart entraînement-service, poser Feast en local, mesurer à nouveau, et — dernière étape — décider honnêtement si le projet valait le coût.
Point de départ : sans magasin
Une petite banque scanne 200 000 paiements par jour. Le scoreur actuel est un XGBoost entraîné toutes les semaines sur un notebook pandas, servi via un microservice Java qui recalcule les cinq variables lui-même à chaque appel, en interrogeant une base opérationnelle PostgreSQL.
Les cinq variables sont celles du fil rouge : nb_transactions_1h, nb_transactions_24h, nb_transactions_7j, montant_moyen_24h, distance_dernier_achat_km. Le modèle affiche un AUC de validation de 0,94 et un rappel de 72 % à précision 50 %. Les indicateurs semblent bons.
Étape 1 : mesurer l'écart. On rejoue sur 30 jours d'historique récent, avec deux calculs de variables — celui du notebook (pandas), celui du microservice (SQL sur PostgreSQL). Pour chaque paiement, on compare la valeur des cinq variables. Résultat : désaccord moyen de 8,3 %, dominé par distance_dernier_achat_km (17 %) où le notebook utilise la formule de Haversine et le microservice une distance euclidienne. On reproduit alors l'entraînement en utilisant les variables du microservice au moment du paiement (en simulant la latence). Le rappel réel tombe à 58 %. Les 14 points de rappel perdus correspondent à environ 420 000 $/mois de fraude non détectée.
Étape 2 : monter le magasin
On crée le dépôt Feast du module 7 :
scoreur_fraude/
├── feature_store.yaml # provider local, Redis en online
├── definitions.py # entité porteur, 1 vue, 5 variables
└── data/transactions.parquet # 90 jours d'historique
feast apply publie la définition. On demande à l'équipe d'ingénierie logicielle d'écrire la matérialisation en incrémental toutes les 15 minutes, avec filtrage sur les porteurs actifs. Ce travail prend deux semaines : une pour convenir des définitions (revue croisée avec la fraude et le marketing), une pour outiller la matérialisation et le service.
Étape 3 : réentraîner sur des variables saines
On génère la table d'entraînement avec get_historical_features sur 90 jours de paiements étiquetés. La jointure point-en-temps du module 5 remplace la jointure USING (card_id_hash) du notebook original. Nouvelle table : mêmes lignes, mais chaque valeur de variable est celle qu'un appel get_online_features aurait renvoyée au moment de la transaction.
Nouveau modèle réentraîné. AUC de validation : 0,88 — plus bas qu'avant. C'est le signe attendu au module 5 : le modèle précédent surestimait grâce à la fuite du futur. Ce qu'on veut vraiment, c'est le rappel réel en production.
Étape 4 : mesurer à nouveau
Déploiement en shadow pendant deux semaines : le nouveau modèle scorent en parallèle du modèle en place, ses prédictions sont enregistrées mais pas appliquées. À la fin des deux semaines, on compare :
| Configuration | AUC validation | Rappel réel (précision 50 %) | Latence p99 |
|---|---|---|---|
| Modèle initial, service qui recalcule | 0,94 | 58 % | 42 ms |
| Nouveau modèle, service qui lit Feast (Redis local) | 0,88 | 71 % | 27 ms |
Le rappel réel gagne 13 points. La latence baisse aussi : la lecture Redis en 4 ms remplace un SELECT ... GROUP BY PostgreSQL en 22 ms. Le gain financier annualisé est estimé à 4,8 M/an. Le magasin s'est amorti en moins d'un mois.
Étape 5 : surveiller
On branche les quatre axes du module 9. Un tableau de bord Grafana affiche fraîcheur, taux de valeurs manquantes, indice de stabilité, désaccord hors ligne/en ligne. Trois mois plus tard, une alerte de niveau 1 se déclenche : la matérialisation ne finit plus dans les temps. Cause : le processeur de paiement a ajouté une nouvelle catégorie de transactions, qui a fait bondir le volume. L'incident est détecté en 40 minutes, corrigé en 90 minutes. Avant, il aurait été détecté à J+30 par l'analyse mensuelle des fraudes.
Ce qu'il aurait fallu pour s'en passer
La question mérite d'être posée honnêtement, parce qu'un magasin est un investissement lourd (deux semaines d'ingénierie, une pile d'infrastructure à opérer). Trois cas où il ne se justifie pas :
Un seul modèle, un seul consommateur, peu de variables. Si l'équipe fraude est seule à consommer trois variables simples, un microservice bien écrit avec une seule source de vérité (une fonction Python partagée entre entraînement et service) fait la même chose, à un coût moindre. La règle : le magasin devient rentable à plus d'un modèle ou plus d'une équipe consommatrice.
Latence non contrainte. Si le modèle est appelé en batch une fois par nuit, sur 100 000 lignes, il n'a pas besoin d'un magasin en ligne. Un entrepôt suffit, et la jointure point-en-temps s'écrit en SQL une fois.
Variables toutes en flux. Si toutes les variables sont temps réel et déjà calculées par un pipeline Kafka Streams, le magasin ne fait que ranger. À moins qu'on ait besoin de l'historique hors ligne, un cache Redis directement piloté par le pipeline est plus simple.
Dans notre projet de fraude, aucun des trois cas ne s'appliquait : plusieurs équipes (fraude + marketing), latence contrainte, mélange batch et flux. Le magasin valait son coût. Mais chaque équipe doit refaire l'exercice, chiffres en main, plutôt que d'adopter par mode.
Grille rapide : combien de modèles consomment les mêmes variables ? Quelle est la latence exigée ? Le calcul est-il par lot, en flux, ou mélangé ? Combien d'équipes co-maintiennent le catalogue ? Un score de 0 ou 1 sur cette grille recommande de ne pas monter un magasin ; un score de 3 ou 4 le rend presque obligatoire.
En résumé
- Sur le cas de fraude, un écart de 8 % sur les variables a fait perdre 14 points de rappel ; le magasin les rattrape.
- La latence baisse aussi, parce que Redis remplace la base opérationnelle pour la lecture — bonus non anticipé.
- La surveillance en amont détecte les incidents en minutes, là où l'aval les découvre en semaines.
- Un magasin n'est pas toujours nécessaire : un modèle, un consommateur et pas de contrainte de latence justifient un microservice bien écrit à la place.
Module suivant : le récapitulatif complet du cours et la préparation à l'examen de 40 questions.