logoScott

Pipeline de Détection de Fraude en Temps Réel

Comment j’ai construit un système de scoring ML de bout en bout avec LightGBM, Kafka, Spark Streaming et de l’observabilité de production.

SScott Santinhole 28 mars 2026
fraud detection pipeline architecture diagram

Pourquoi ce projet existe

La plupart des projets de détection de fraude qu’on trouve en ligne s’arrêtent au notebook. On entraîne un modèle, on affiche un score AUC-ROC, on trace peut-être une matrice de confusion, et c’est terminé. Mais dans le monde réel, un modèle qui reste dans un Jupyter notebook ne détecte rien.

Je voulais aller plus loin : entraîner un modèle, le brancher sur un pipeline de micro-batching, et le regarder scorer des transactions au fil de l’eau, avec du routage, de la tolérance aux pannes et du monitoring intégrés. Pas parce que le dataset l’exigeait (c’est un CSV Kaggle), mais parce que c’est après le notebook que les vrais défis techniques commencent.

C’était aussi l’occasion de monter un vrai pipeline de micro-batching from scratch. J’avais déjà utilisé Spark en mode batch, mais jamais câblé de bout en bout avec Kafka, PostgreSQL et Prometheus dans un seul stack Docker Compose. Le cas d’usage fraude m’a fourni une charge de travail concrète et réaliste pour le mettre à l’épreuve.

En bref : le modèle ML est un moyen, pas une fin. Le vrai projet, c’est le pipeline autour.

Le volet ML

Le dataset utilisé est l’IEEE-CIS Fraud Detection de Kaggle : 590 000 transactions par carte bancaire, 434 features, et un taux de fraude de 3,5 %. Le déséquilibre de classes est important : la grande majorité des transactions sont légitimes, ce qui rend l’accuracy trompeuse. Je me suis donc appuyé sur l’AUC-ROC et les courbes precision-recall.

L’analyse exploratoire a révélé plusieurs choses. Les V-features (V1–V339) sont anonymisées et beaucoup affichent plus de 70 % de valeurs nulles. Les données d’identité ne couvrent que 24 % des transactions : impossible de s’appuyer en production sur un champ absent les trois quarts du temps. En revanche, l’heure de la journée et les incohérences de domaine email se sont révélées être de bons indicateurs de fraude, d’où la création de ces features.

La sélection de features repose sur une approche hybride :

  • Information Mutuelle pour capturer les dépendances individuelles feature-cible
  • Feature Importance via XGBoost pour capturer les effets d’interaction
  • Fusion des top 50 de chaque méthode, complétée par 5 features de domaine forcées (TransactionAmt, ProductCD, card4, card6, hour)
  • Résultat : 76 features retenues sur les 434 d’origine

J’ai comparé LightGBM et XGBoost via une validation croisée stratifiée à 5 folds. Les deux étaient au coude à coude en CV, mais LightGBM l’a emporté sur le holdout temporel, tout en étant plus rapide à entraîner et moins gourmand en mémoire : un avantage non négligeable quand le scoring tourne dans des executors Spark.

MétriqueValeur
AUC-ROC (holdout)0,8779
PR-AUC (holdout)0,4661
ArchitectureLightGBM : 300 arbres, max_depth=6
Pondération des classesscale_pos_weight=27,46 (pénalise la fraude manquée 27×)

Un choix délibéré : le holdout est temporel (premiers 80 % des jours pour l’entraînement, derniers 20 % pour le test), et non un split aléatoire. Les patterns de fraude évoluent dans le temps : un split aléatoire revient à faire fuiter le futur dans le passé et gonfle artificiellement les scores.

Trois niveaux, pas binaire

La plupart des systèmes anti-fraude raisonnent en binaire : approuver ou bloquer. C’est trop brutal. Un faux positif bloque un client légitime et coûte sa valeur à vie. Un faux négatif laisse passer la fraude et entraîne des remboursements. Il faut un entre-deux.

D’où l’utilisation de deux seuils qui découpent le trafic en trois niveaux :

NiveauPlage de scoreTraficComportement
Approuvé< 0,261,1 %Auto-approuvé, 88,4 % de la fraude détectée avant ce point
En attente0,2 – 0,835,2 %Mis en file pour revue humaine manuelle
Rejeté≥ 0,83,6 %Auto-refusé, précision de 44,7 %

Ces seuils ne sont pas choisis au doigt mouillé mais découlent d’un modèle de coût :

  • Manquer une fraude coûte 3× le montant de la transaction (remboursements + pénalités)
  • Bloquer un client légitime coûte 5× sa valeur à vie (risque de churn)
  • La revue manuelle coûte 5 $ par transaction
  • Les seuils 0,2/0,8 économisent ~400 K$ par rapport à une baseline naïve 0,3/0,7 à 15 % de churn
88,4 % de la fraude est détectée avant même qu’une transaction n’atteigne le niveau d’approbation automatique. Les 11,6 % restants atterrissent en attente de revue, où un humain peut trancher.

Architecture en un coup d’œil

Tout tourne dans un seul Docker Compose : 12 services, zéro dépendance cloud :

ComposantTechnologiePourquoi
File de messagesKafka 4.0 (KRaft)Replay durable, distribué, sans Zookeeper
StreamingSpark 4.0 Structured StreamingMicro-batching tolérant aux pannes, intégration Kafka native
Modèle MLLightGBMRapide, peu gourmand en mémoire, égale XGBoost en précision
Base de donnéesPostgreSQL 18ACID, driver JDBC intégré à Spark
Pool de connexionsPgBouncerPooling en mode transaction entre Spark et PostgreSQL
MonitoringPrometheus + GrafanaStandard industriel, time-series natif, gratuit
SérialisationJSONPas d’évolution de schéma nécessaire pour le replay du dataset
Docker Compose services layout

Scoring en micro-batch

Le job Spark lit depuis Kafka, score chaque micro-batch avec LightGBM, et route les résultats vers trois tables PostgreSQL. Toutes les 5 secondes, un nouveau batch arrive.

Le flux à l’intérieur de chaque micro-batch :

  1. Lecture du JSON depuis Kafka (sélection des 76 champs nécessaires sur 434)
  2. Feature engineering : calcul de l’heure depuis TransactionDT, calcul de email_mismatch
  3. Label encoding : application des mêmes mappings de catégories que l’entraînement
  4. Imputation par médiane : remplissage des nulls avec les médianes calculées à l’entraînement
  5. Scoring distribué : mapInPandas envoie le prétraitement et predict_proba() aux workers Spark via le modèle broadcast
  6. Routage par seuil et écriture avec upsert (INSERT ON CONFLICT DO NOTHING) via PgBouncer vers transactions_approved, transactions_pending_review ou transactions_rejected
  7. Mise à jour des métriques Prometheus (compteurs, histogramme de latence, gauge du taux de fraude)

Le choix architectural clé ici est foreachBatch plutôt que le traitement continu, et ce n’est pas anodin :

Pourquoi foreachBatch ?

  • Écritures multi-sorties : trois tables PostgreSQL différentes par batch, impossible avec un seul sink continu
  • ML distribué : mapInPandas distribue le scoring LightGBM aux workers, avec predict_proba vectorisé sur des tableaux numpy par partition
  • Intégration Prometheus : mise à jour des métriques après chaque batch, pas après chaque ligne
  • Checkpointing : les offsets Kafka sont suivis automatiquement, le redémarrage reprend au dernier batch sans perte de données
Spark Master Web UI

Observabilité

Un pipeline de scoring sans monitoring, c’est naviguer à l’aveugle. Il faut détecter la dérive du modèle, le retard Kafka ou les pics de latence avant que ça ne devienne un problème visible.

MétriqueTypeMesure
transactions_scored_totalCounterTotal de transactions traitées
approved/pending/rejected_totalCountersDistribution du routage
fraud_rateGaugeTaux de rejet (moyenne glissante sur 10 batchs)
null_feature_rateGaugeQualité des données (% moyen de nulls par batch)
batch_sizeGaugeTransactions par micro-batch
scoring_duration_secondsHistogramPercentiles de latence (p50/p95/p99)

Le dashboard Grafana comporte quatre lignes :

  • Santé de l’infrastructure : nombre de brokers, cibles Prometheus, partitions du topic, total scoré
  • Débit Kafka : taux de production par partition, retard du consumer group dans le temps
  • Scoring ML : gauge du taux de fraude (code couleur), taille des batchs, latence du scoring
  • Performance : percentiles de latence dans le temps (p50/p95/p99)
Grafana pipeline health dashboard

Trois règles d’alerte détectent les problèmes en amont :

  • Pic de retard consommateur : lag > 100 pendant 30s → Warning (le scorer est peut-être arrêté)
  • Anomalie du taux de fraude : taux de rejet > 5 % pendant 1min → Critical (dérive du modèle ou données corrompues)
  • Latence de scoring élevée : p95 > 5s pendant 1min → Warning (santé des executors dégradée)

Lire le détail technique

Le code complet est documenté dans le repo : notebooks ML, pipeline Spark, producteur Kafka, stack Docker Compose, dashboards Grafana et règles d’alerte.

BIENTÔT DISPONIBLE