Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 

Repository files navigation

🛡️ Fraud Model Validator v2.0

Framework professionnel de validation de modèles de détection de fraude et de criminalité financière (FinCrime), conforme aux standards réglementaires SR 11-7, ECB TRIM Guide, AMLD6 et Bâle III/IV.

Python License Standards Sklearn


📋 Table des matières

  1. Vue d'ensemble
  2. Contenu du dépôt
  3. Installation
  4. Le jeu de données
  5. Architecture du validateur
  6. Modules de validation
  7. Démarrage rapide
  8. Interprétation des résultats
  9. Référentiel réglementaire
  10. Dépendances
  11. FAQ

🎯 Vue d'ensemble

La validation de modèle est une exigence non négociable dans le secteur financier. Un modèle de détection de fraude avec un excellent AUC sur le jeu de test peut néanmoins échouer en production pour plusieurs raisons :

  • Les distributions de scores dérivent dans le temps (PSI élevé)
  • Les probabilités prédites ne sont pas calibrées (ECE > 0.05)
  • Le modèle discrimine différemment selon les groupes protégés (biais)
  • Les données d'entraînement ont été manipulées (Benford non-conforme)
  • La performance s'effondre sous certains scénarios de stress (Bâle III)

Ce framework adresse tous ces risques de façon systématique et traçable.

┌─────────────────────────────────────────────────────────────────┐
│               FRAUD MODEL VALIDATOR v2.0 — FLUX                 │
│                                                                  │
│  Données      ──►  Modèle      ──►  FraudModelValidatorV2       │
│  (CSV/DF)          (sklearn)         │                           │
│                                      ├── Performance (AUC, KS…) │
│                                      ├── Calibration (ECE, BSS) │
│                                      ├── Lift & Gains           │
│                                      ├── Stabilité (PSI/CSI)    │
│                                      ├── Benford's Law          │
│                                      ├── Graph Anomaly          │
│                                      ├── Fairness               │
│                                      ├── Threshold Optim.       │
│                                      ├── Stress Tests           │
│                                      ├── Walk-Forward BT        │
│                                      └── Rapport HTML ◄─────────┤
└─────────────────────────────────────────────────────────────────┘

📁 Contenu du dépôt

fraud-model-validator/
│
├── Fraud_Model_Validator_v2.py   # Validateur principal (2 000+ lignes)
├── fraud_dataset.csv             # Dataset complet — 50 000 transactions
├── fraud_dataset.xlsx            # Dataset Excel — 4 feuilles annotées
└── README.md                     # Ce fichier

Description des fichiers

Fichier Taille Description
Fraud_Model_Validator_v2.py ~2 100 lignes Classe FraudModelValidatorV2 + démo complète
fraud_dataset.csv 7,7 Mo 50 000 transactions, 30 colonnes, 4 typologies de fraude
fraud_dataset.xlsx 1,6 Mo Version Excel : Transactions (10k) + Stats + Dictionnaire + Guide

⚙️ Installation

Prérequis

  • Python 3.9+
  • pip

Dépendances obligatoires

pip install pandas numpy scikit-learn matplotlib scipy

Dépendances optionnelles (fortement recommandées)

# Explainabilité (SHAP values)
pip install shap

# Analyse du réseau de transactions (Graph Anomaly Detection)
pip install networkx

# Export Excel du dataset
pip install openpyxl

Installation complète en une ligne

pip install pandas numpy scikit-learn matplotlib scipy shap networkx openpyxl

Vérification

from Fraud_Model_Validator_v2 import FraudModelValidatorV2
validator = FraudModelValidatorV2("test")
print("✅ Installation OK")

🗃️ Le jeu de données

Composition

Le fichier fraud_dataset.csv contient 50 000 transactions bancaires simulées avec des propriétés statistiques calquées sur des données réelles de détection de fraude.

Classe Effectif %
Légitimes 48 000 96,0%
Fraudes 2 000 4,0%
Total 50 000 100%

Note sur le déséquilibre de classes : Un taux de fraude de 4% est volontairement réaliste (les banques retail observent généralement 0,5% à 5%). Il implique d'utiliser des métriques adaptées au déséquilibre : AUCPR, F1, MCC — et non l'accuracy brute qui serait trompeuse.

Les 4 typologies de fraude

1. 💳 CNP — Card-Not-Present / E-commerce (40% des fraudes)

Fraude la plus courante dans le commerce en ligne. Le fraudeur utilise des coordonnées bancaires volées pour des achats à distance.

Signature dans les données :

  • transaction_amount : élevé (lognormal µ=5.5)
  • hour_of_day : nocturne (0h–6h, 22h–24h)
  • auth_method : no_auth dans 75% des cas
  • ip_risk_score : élevé (Beta(7,2))
  • is_international : 65% de transactions transfrontalières

2. 🏧 Smurfing / Fractionnement (25% des fraudes)

Technique de blanchiment d'argent : fragmenter de grosses sommes en multiples petites transactions pour passer sous les seuils de déclaration réglementaires (1 000€ en France, 10 000$ aux États-Unis).

Signature dans les données :

  • transaction_amount : systématiquement entre 490€ et 999€ (juste sous le seuil de 1 000€)
  • transaction_velocity_1h : très élevée (Poisson λ=12)
  • receiver_id : concentré sur un petit nombre de destinataires
  • nb_cards_last_30d : 3 à 7 cartes différentes
  • Signal fort pour la Loi de Benford (les montants ne suivent pas la distribution naturelle)

3. 🔐 Account Takeover — ATO (20% des fraudes)

Compromission de compte légitime : le fraudeur prend le contrôle d'un compte existant (phishing, credential stuffing, SIM swapping) et effectue des transactions.

Signature dans les données :

  • is_new_device : 1 dans presque 100% des cas (le fraudeur utilise son propre appareil)
  • failed_auth_last_24h : très élevé (3 à 8 échecs avant de réussir)
  • hour_of_day : tôt le matin (1h–7h)
  • distance_from_home_km : très élevée (le fraudeur est ailleurs)
  • device_risk_score et ip_risk_score : très élevés

4. 🕵️ Fraude Interne / Insider (15% des fraudes)

Fraude commise par un employé ou un complice interne. La plus difficile à détecter car le profil ressemble à un utilisateur légitime.

Signature dans les données :

  • hour_of_day : horaires de bureau (9h–18h) — se fond dans la masse
  • day_of_week : jours ouvrés (lundi–vendredi)
  • distance_from_home_km : faible (transaction depuis le bureau)
  • is_new_device : faible (appareil connu)
  • device_risk_score et ip_risk_score : modérés — signal discret

Dictionnaire des variables

Variable Type Description Signal Fraude
transaction_id str Identifiant unique (TXNxxxxxx)
customer_id str Identifiant client (CUSTxxxx)
transaction_date datetime Horodatage YYYY-MM-DD HH:MM ★★★
sender_id int ID émetteur pour analyse graphe [1–8000] ★★★
receiver_id int ID destinataire pour analyse graphe [1–5000] ★★★★
transaction_amount float Montant en € (lognormal) ★★★★
avg_amount_30d float Montant moyen des 30 derniers jours ★★★
amount_vs_avg_ratio float Ratio montant / moyenne 30j ★★★★
transaction_velocity_1h int Nb de transactions dans la dernière heure ★★★★★
transaction_velocity_24h int Nb de transactions dans les dernières 24h ★★★★
merchant_name str Nom du marchand (25 valeurs) ★★
merchant_risk_score float Score de risque marchand [0,1] ★★★
customer_age_days int Ancienneté du compte en jours ★★★★
is_international int Transaction internationale 0/1 ★★★
is_new_device int Appareil non enregistré 0/1 ★★★★
is_new_merchant int Marchand jamais utilisé 0/1 ★★★
hour_of_day int Heure de la transaction [0–23] ★★★
day_of_week int Jour de la semaine [0=Lun…6=Dim] ★★
device_type str mobile_android / mobile_ios / desktop / tablet ★★
auth_method str 3DS / PIN / biometric / signature / no_auth ★★★★
device_risk_score float Score de risque appareil [0,1] ★★★★
ip_risk_score float Score de risque adresse IP [0,1] ★★★★
distance_from_home_km float Distance depuis le domicile en km ★★★
nb_cards_last_30d int Nb de cartes différentes utilisées (30j) ★★★
failed_auth_last_24h int Nb d'échecs d'authentification (24h) ★★★★★
chargeback_rate_6m float Taux de rétrofacturation sur 6 mois [0,1] ★★★★
country_origin str Pays d'émission (ISO alpha-2) ★★★
currency str EUR / USD / GBP / CHF ★★
fraud_type str CNP / smurfing / account_takeover / insider / none INFO
is_fraud int 🎯 Variable cible — 0=légitime, 1=fraude TARGET

Statistiques comparatives clés

Feature Moy. Légitime Moy. Fraude Ratio F/L
transaction_amount (€) ~65 ~490 ×7.5
transaction_velocity_1h ~1.5 ~8.0 ×5.3
failed_auth_last_24h ~0.1 ~3.5 ×35
device_risk_score ~0.12 ~0.68 ×5.7
ip_risk_score ~0.11 ~0.72 ×6.5
distance_from_home_km ~15 ~320 ×21
chargeback_rate_6m ~0.05 ~0.45 ×9.0

🏗️ Architecture du validateur

Instanciation

from Fraud_Model_Validator_v2 import FraudModelValidatorV2

validator = FraudModelValidatorV2(
    model_name = "MonModèle_GBM_v1",   # Nom affiché dans les rapports
    cost_fn    = 5000,                  # Coût d'un faux négatif (fraude manquée) en €
    cost_fp    = 100,                   # Coût d'un faux positif (fausse alarme) en €
    currency   = "€"                    # Symbole monétaire pour l'affichage
)

Pourquoi paramétrer les coûts ? En détection de fraude, les coûts sont très asymétriques : manquer une fraude (FN) coûte souvent 10 à 100 fois plus cher qu'une fausse alerte (FP). Paramétrer ces coûts permet d'optimiser le seuil de décision de façon économiquement rationnelle plutôt qu'en maximisant naïvement le F1-score.


📐 Modules de validation

1. Performance discriminante

metrics = validator.calculate_performance_metrics(
    y_true        = y_test,
    y_pred_proba  = y_proba,
    threshold     = 0.5,
    bootstrap     = True,     # Activer les intervalles de confiance
    n_bootstrap   = 1000      # Nb d'itérations (1000 recommandé en prod)
)

Métriques calculées :

Métrique Description Bon seuil (fraude)
AUC-ROC Aire sous la courbe ROC. Mesure la capacité à séparer les classes. ≥ 0.80
GINI 2 × AUC - 1. Version normalisée entre 0 et 1. ≥ 0.60
KS-Statistic Écart maximum entre les CDF des deux classes. ≥ 0.40
H-measure Alternative à l'AUC (Hand 2009) qui intègre l'asymétrie des coûts. ≥ 0.30
Average Precision AUC de la courbe Precision-Recall, plus adaptée aux classes déséquilibrées. ≥ 0.60
MCC Matthews Correlation Coefficient. Seule métrique fiable sur toutes les configurations de matrice de confusion. ≥ 0.50
Brier Score Erreur quadratique moyenne sur les probabilités. 0 = parfait. ≤ 0.05

Bootstrap CI 95% : pour chaque métrique clé, l'IC bootstrap donne une idée de la variance d'estimation et de la robustesse du modèle. Un IC large signale un modèle instable ou un jeu de test trop petit.


2. Calibration probabiliste

cal_results = validator.calibration_analysis(
    y_true       = y_test,
    y_pred_proba = y_proba,
    n_bins       = 10
)

Pourquoi la calibration est critique ?

Un modèle peut avoir un excellent AUC tout en étant mal calibré : si le modèle prédit P(fraude) = 0.8 mais que le taux réel de fraude dans ce groupe n'est que de 40%, les équipes risque prendront de mauvaises décisions sur les seuils d'alerte.

Métriques calculées :

Métrique Description Interprétation
Brier Score Erreur quadratique moyenne < 0.05 = excellent
Brier Skill Score BSS normalisé par la climatologie (taux de base). 1 = parfait, 0 = pas mieux qu'un modèle naïf. > 0.50
ECE Expected Calibration Error : erreur de calibration moyenne pondérée par la taille des bins. < 0.02
MCE Maximum Calibration Error : pire erreur de calibration observée dans un bin. < 0.05

Reliability Diagram : graphique clé qui compare les probabilités prédites aux fréquences observées. Une droite parfaite à 45° indique une calibration parfaite.


3. Lift & Gains Analysis

lift_df = validator.lift_gain_analysis(
    y_true       = y_test,
    y_pred_proba = y_proba,
    deciles      = 10
)

Interprétation du Lift :

Le lift mesure combien de fois le modèle est meilleur qu'un ciblage aléatoire dans chaque décile. Un lift de 8.0 dans le décile 1 signifie que les 10% de transactions avec les scores les plus élevés contiennent 8 fois plus de fraudes que la moyenne.

Décile 1 (top 10% scores) → Lift = 8.0 → 80% des fraudes dans 10% du volume
Décile 2                   → Lift = 4.0
Décile 3                   → Lift = 2.0
...
Décile 10 (scores faibles) → Lift ≈ 0.1 (quasi aucune fraude)

Utilité opérationnelle : permet de dimensionner les équipes de revue manuelle — si les analystes ne peuvent traiter que 5% des transactions, combien de fraudes vont-ils capturer ?


4. Stabilité — PSI & CSI

# PSI temporel sur le score
stability_df = validator.stability_analysis(
    df          = df_with_scores,
    score_col   = 'score',
    date_col    = 'transaction_date',
    period      = 'M'              # 'M' = mensuel, 'W' = hebdo, 'Q' = trimestriel
)

# CSI par feature
csi_df = validator.feature_stability_index(
    df_ref       = df_reference,   # Période de référence (ex: train set)
    df_cur       = df_current,     # Période courante (ex: production)
    feature_cols = feature_cols,
    bins         = 10
)

PSI — Population Stability Index :

Le PSI mesure si la distribution des scores a changé entre deux périodes. C'est l'indicateur standard de dérive de modèle.

PSI Interprétation Action
< 0.10 ✅ Stable — Pas d'action nécessaire Surveillance normale
0.10 – 0.25 ⚠️ Dérive modérée — Investiguer Analyse des causes
> 0.25 🚨 Dérive critique — Retraining probable Alerte réglementaire

CSI — Characteristic Stability Index : le PSI appliqué à chaque feature individuellement. Permet d'identifier quelle variable est responsable de la dérive du score.


5. Loi de Benford

benford_results = validator.benford_law_analysis(
    df          = df,
    amount_col  = 'transaction_amount'
)

Qu'est-ce que la loi de Benford ?

Dans tout jeu de données naturel (montants, populations, prix de marché…), le premier chiffre significatif suit une distribution logarithmique prévisible :

Chiffre Fréquence attendue
1 30,1%
2 17,6%
3 12,5%
4 9,7%
5 7,9%
... ...
9 4,6%

Pourquoi c'est un signal de fraude ?

  • Le smurfing crée des montants artificiels juste sous les seuils → sur-représentation des chiffres 4, 9 (490€, 990€)
  • Le round-tripping produit des montants ronds → sur-représentation du chiffre 1 (1000€, 10000€)
  • La falsification comptable génère des patterns non-naturels détectables statistiquement

Métriques :

  • MAD (Mean Absolute Deviation) : < 0.006 = conforme, > 0.015 = non-conforme
  • χ² p-value : si p < 0.05, la déviation est statistiquement significative
  • Z-scores par chiffre : identifie quels chiffres sont sur ou sous-représentés

6. Graph Anomaly Detection

graph_df = validator.graph_anomaly_detection(
    df          = df.sample(10000),   # Échantillon suffisant
    source_col  = 'sender_id',
    target_col  = 'receiver_id',
    amount_col  = 'transaction_amount',
    fraud_col   = 'is_fraud'          # Optionnel, pour évaluation
)

Pourquoi une approche graphe ?

Les modèles tabulaires traitent chaque transaction indépendamment. Ils ne voient pas que :

  • CUST_123 envoie de l'argent à 50 receivers différents en 24h (hub de smurfing)
  • Un ensemble de comptes forme un cycle de transactions (round-tripping)
  • Certains receivers concentrent une part anormale des transactions frauduleuses

Métriques calculées par nœud (entité) :

Métrique Description
Degree (in/out) Nb de connexions entrantes/sortantes
PageRank Influence systémique dans le réseau (comme Google pour les pages web)
Betweenness centrality Le nœud est-il un "pont" structurel dans le réseau ? Les mules financières ont souvent une betweenness élevée.
Score d'anomalie composite Moyenne des Z-scores standardisés de toutes les métriques

Interprétation : les nœuds avec un score d'anomalie composite élevé méritent une investigation manuelle, indépendamment de leurs scores individuels de transaction.


7. Permutation Feature Importance

imp_df = validator.permutation_feature_importance(
    model        = trained_model,
    X            = X_test,
    y            = y_test,
    n_repeats    = 10,              # Stabilité de l'estimation
    feature_names = feature_cols
)

Pourquoi préférer la permutation importance à l'importance impurity-based (MDI) ?

L'importance par impureté des forêts et GBM est biaisée en faveur des features à haute cardinalité et peut masquer des features inutiles ou corrélées. La permutation importance mesure directement l'impact sur la métrique de validation (AUC-ROC) en permutant aléatoirement les valeurs d'une feature et en observant la chute de performance. C'est la mesure la plus fiable et la plus interprétable.

Sortie : DataFrame avec importance_mean ± 1.96σ (IC 95%) pour chaque feature, trié par importance décroissante. Une feature avec un IC incluant 0 n'apporte pas de valeur significative.


8. Fairness Analysis

fairness_df, summary = validator.fairness_analysis(
    df             = df_eval,
    score_col      = 'score',
    target_col     = 'is_fraud',
    protected_attr = 'is_international',   # Attribut protégé
    threshold      = 0.5
)

Métriques d'équité calculées :

Métrique Description Seuil réglementaire
TPR gap (Equalized Odds) Différence de taux de détection entre groupes < 0.10
FPR gap Différence de taux de fausse alarme entre groupes < 0.10
Disparate Impact Ratio Ratio des taux de classification positive. DIR < 0.80 = discrimination prima facie (règle des 4/5, EEOC). ≥ 0.80
Test KS inter-groupes Les distributions de scores sont-elles significativement différentes ? p > 0.05
Test χ² Indépendance entre l'attribut protégé et la décision p > 0.05

9. Optimisation du seuil

best_threshold, results_df, optimal_thresholds = validator.optimize_threshold(
    y_true       = y_test,
    y_pred_proba = y_proba,
    metric       = 'cost'    # 'f1', 'mcc', 'cost', 'gmean', 'youden_j'
)

Stratégies disponibles :

Stratégie Optimise Quand l'utiliser
cost Coût total FN×cost_fn + FP×cost_fp Recommandé en production : aligne la décision sur l'économie réelle
f1 F1-Score Équilibre précision/recall sans information de coût
mcc Matthews Correlation Coefficient Robuste au déséquilibre de classes
gmean Moyenne géométrique TPR×TNR Maximise simultanément sensibilité et spécificité
youden_j Statistique J de Youden (TPR − FPR) Équivalent au KS-statistic pour le choix de seuil

Conseil : en conditions réelles, utiliser toujours metric='cost' avec des coûts reflétant l'économie du produit (coût d'une fraude manquée vs coût d'un faux positif en termes d'expérience client et de revue manuelle).


10. Stress Testing réglementaire

stress_df = validator.stress_test(
    X                    = X_test,
    y_true               = y_test,
    model_predict_fn     = lambda X: model.predict_proba(X)[:,1],
    perturbation_factors = [0.5, 0.8, 1.2, 1.5, 2.0, 3.0]
)

Scénarios testés :

Catégorie Scénario Exigence réglementaire
Choc Montants Montants ×0.5 à ×3.0 Bâle III — résistance aux pics de marché
Robustesse Bruit Bruit gaussien σ=5%, 10%, 20%, 50% SR 11-7 — robustesse aux données dégradées
Data Quality Suppression de 1, 2, 3 features Continuité d'activité — données manquantes
Concept Drift Taux fraude ×1.5, ×2.0 Bâle III — scénario adverse
Black Swan Taux fraude ×5.0 AMLD6 — scénario de crise systémique

Lecture des résultats :

  • auc_drop_pct < 5% → ✅ Modèle robuste
  • auc_drop_pct 5–10%⚠️ Plan de mitigation requis
  • auc_drop_pct > 10% → 🚨 Modèle fragile — retraining ou garde-fou nécessaire

11. Walk-Forward Backtesting

wf_df = validator.walk_forward_backtest(
    df           = df,
    model        = GradientBoostingClassifier(n_estimators=150),
    feature_cols = feature_cols,
    target_col   = 'is_fraud',
    date_col     = 'transaction_date',
    n_splits     = 5,
    min_train_size = 0.5    # 50% minimum pour l'entraînement initial
)

Pourquoi le walk-forward et pas la cross-validation standard ?

La CV standard avec shuffle=True permet au modèle de s'entraîner sur des données futures par rapport au jeu de test. C'est un look-ahead bias qui produit des estimations de performance trop optimistes.

CV Standard (incorrect pour les séries temporelles) :
  Train: [Jan, Mar, May, Jul]  Test: [Feb, Apr, Jun, Aug]  ← Le futur prédit le passé!

Walk-Forward (correct) :
  Fold 1: Train [Jan–Jun]       → Test [Jul–Aug]
  Fold 2: Train [Jan–Aug]       → Test [Sep–Oct]
  Fold 3: Train [Jan–Oct]       → Test [Nov–Dec]
  ...                                                        ← Toujours le passé prédit le futur

Signal d'alerte : un écart-type d'AUC > 0.03 entre les folds indique une instabilité temporelle — le modèle pourrait dériver rapidement en production.


12. Rapport HTML

validator.generate_html_report(
    output_path = 'rapport_validation.html'
)

Génère un rapport HTML standalone (pas de dépendance externe, tout est encodé en base64) incluant :

  • Score global pondéré sur 100
  • Badges de conformité réglementaire (vert/orange/rouge)
  • Toutes les figures en haute résolution
  • Tableau de KPIs clés
  • Matrice d'alertes automatiques

🚀 Démarrage rapide

Exemple complet minimal (5 minutes)

import pandas as pd
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from Fraud_Model_Validator_v2 import FraudModelValidatorV2

# ── 1. Chargement des données ──────────────────────────────────────────────
df = pd.read_csv('fraud_dataset.csv', parse_dates=['transaction_date'])

feature_cols = [
    'transaction_amount', 'avg_amount_30d', 'amount_vs_avg_ratio',
    'transaction_velocity_1h', 'transaction_velocity_24h',
    'merchant_risk_score', 'customer_age_days', 'is_international',
    'is_new_device', 'is_new_merchant', 'hour_of_day', 'day_of_week',
    'device_risk_score', 'ip_risk_score', 'distance_from_home_km',
    'nb_cards_last_30d', 'failed_auth_last_24h', 'chargeback_rate_6m'
]
X = df[feature_cols]
y = df['is_fraud']

# ── 2. Entraînement du modèle ──────────────────────────────────────────────
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, stratify=y, random_state=42
)
scaler = StandardScaler()
model  = GradientBoostingClassifier(n_estimators=150, learning_rate=0.08,
                                     max_depth=5, random_state=42)
model.fit(scaler.fit_transform(X_train), y_train)
y_proba = model.predict_proba(scaler.transform(X_test))[:, 1]

# ── 3. Validation ──────────────────────────────────────────────────────────
validator = FraudModelValidatorV2("GBM_v1", cost_fn=5000, cost_fp=100)

metrics  = validator.calculate_performance_metrics(y_test.values, y_proba, bootstrap=True)
_        = validator.plot_advanced_curves(y_test.values, y_proba)
lift_df  = validator.lift_gain_analysis(y_test.values, y_proba)
cal      = validator.calibration_analysis(y_test.values, y_proba)
benford  = validator.benford_law_analysis(df)

# ── 4. Rapport HTML ────────────────────────────────────────────────────────
validator.generate_html_report('rapport_validation.html')
print("✅ Rapport généré !")

Exemple complet avancé (validation réglementaire complète)

import pandas as pd
import numpy as np
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from Fraud_Model_Validator_v2 import FraudModelValidatorV2

df = pd.read_csv('fraud_dataset.csv', parse_dates=['transaction_date'])

feature_cols = [
    'transaction_amount', 'avg_amount_30d', 'amount_vs_avg_ratio',
    'transaction_velocity_1h', 'transaction_velocity_24h',
    'merchant_risk_score', 'customer_age_days', 'is_international',
    'is_new_device', 'is_new_merchant', 'hour_of_day', 'day_of_week',
    'device_risk_score', 'ip_risk_score', 'distance_from_home_km',
    'nb_cards_last_30d', 'failed_auth_last_24h', 'chargeback_rate_6m'
]
X, y = df[feature_cols], df['is_fraud']

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, stratify=y, random_state=42
)
scaler = StandardScaler()
model  = GradientBoostingClassifier(n_estimators=150, random_state=42)
model.fit(scaler.fit_transform(X_train), y_train)
y_proba = model.predict_proba(scaler.transform(X_test))[:, 1]
predict_fn = lambda X_in: model.predict_proba(scaler.transform(X_in))[:, 1]

validator = FraudModelValidatorV2("GBM_CompletDemo", cost_fn=5000, cost_fp=100)

# Performance + Bootstrap CI
metrics = validator.calculate_performance_metrics(y_test.values, y_proba, bootstrap=True)

# Courbes diagnostiques (ROC, PR, DET, KS)
validator.plot_advanced_curves(y_test.values, y_proba)

# Lift & Gains
lift_df = validator.lift_gain_analysis(y_test.values, y_proba)

# Calibration (ECE, MCE, BSS, Reliability Diagram)
cal = validator.calibration_analysis(y_test.values, y_proba)

# Stabilité temporelle (PSI + KS drift)
df_s = X_test.copy()
df_s['score'] = y_proba
df_s['transaction_date'] = df['transaction_date'].iloc[X_test.index].values
stability = validator.stability_analysis(df_s)

# CSI par feature
half = len(df) // 2
csi_df = validator.feature_stability_index(
    df.iloc[:half][feature_cols], df.iloc[half:][feature_cols], feature_cols
)

# Benford's Law
benford = validator.benford_law_analysis(df, amount_col='transaction_amount')

# Graph Anomaly Detection
graph_df = validator.graph_anomaly_detection(
    df.sample(8000, random_state=42),
    source_col='sender_id', target_col='receiver_id',
    amount_col='transaction_amount', fraud_col='is_fraud'
)

# Permutation Feature Importance
imp_df = validator.permutation_feature_importance(
    model, scaler.transform(X_test), y_test.values,
    feature_names=feature_cols, n_repeats=10
)

# Mahalanobis + Isolation Forest
anomaly_scores = validator.mahalanobis_outlier_detection(X_test, contamination=0.05)

# Fairness Analysis
df_eval = X_test.copy()
df_eval['score'], df_eval['is_fraud'] = y_proba, y_test.values
fairness_df, summary = validator.fairness_analysis(
    df_eval, 'score', 'is_fraud', 'is_international'
)

# Threshold Optimization multi-critères
best_t, thresh_df, optimal = validator.optimize_threshold(
    y_test.values, y_proba, metric='cost'
)

# Stress Testing réglementaire (Bâle III + AMLD6)
stress_df = validator.stress_test(X_test, y_test.values, predict_fn)

# Cross-Validation stratifiée
cv_df = validator.cross_validate(
    X, y, GradientBoostingClassifier(n_estimators=80), n_splits=5
)

# Walk-Forward Backtesting
wf_df = validator.walk_forward_backtest(
    df, GradientBoostingClassifier(n_estimators=80),
    feature_cols, 'is_fraud', 'transaction_date', n_splits=5
)

# Rapport texte
validator.generate_validation_report(
    metrics=metrics, stability_df=stability,
    stress_df=stress_df, cv_df=cv_df,
    output_path='rapport_validation.txt'
)

# Rapport HTML interactif
validator.generate_html_report('rapport_validation.html')

📊 Interprétation des résultats

Performances attendues sur ce dataset

Avec un GradientBoostingClassifier(n_estimators=150) et StandardScaler :

Métrique Valeur typique Interprétation
AUC-ROC 0.96 – 0.98 Excellent — séparation quasi-parfaite
GINI 0.92 – 0.96 Excellent
KS-Statistic 0.80 – 0.90 Excellent — forte séparation des CDF
Average Precision 0.85 – 0.95 Très bon malgré le déséquilibre
F1-Score (@0.5) 0.80 – 0.90 Bon équilibre précision/recall
Brier Score 0.01 – 0.03 Bonne calibration
Lift (décile 1) 6× – 9× Cibler le top 10% capture ~70-80% des fraudes

Ces performances élevées reflètent des features synthétiques fortement discriminantes. En conditions réelles, avec du bruit de mesure, des données manquantes et des fraudeurs adaptatifs, les AUC se situent plutôt entre 0.80 et 0.92.

Grille d'évaluation réglementaire

Critère Seuil minimal Seuil satisfaisant Excellent
AUC-ROC 0.70 0.80 ≥ 0.90
KS-Statistic 0.30 0.40 ≥ 0.60
PSI (stabilité) < 0.25 < 0.10 < 0.05
ECE (calibration) < 0.05 < 0.02 < 0.01
Disparate Impact ≥ 0.80 ≥ 0.90 ≈ 1.00
AUC drop (stress) < 15% < 10% < 5%

📜 Référentiel réglementaire

Ce framework est conçu pour répondre aux exigences de :

SR 11-7 (Federal Reserve, 2011)

Directive phare sur la gestion des risques liés aux modèles. Exige une validation indépendante couvrant : la solidité conceptuelle, les données d'entraînement, les performances out-of-sample, et la surveillance continue.

ECB TRIM Guide (Targeted Review of Internal Models, 2017–2021)

Guide de la BCE pour la revue des modèles internes bancaires. Exige notamment la validation de la stabilité, la backtesting, et la documentation des choix de modélisation.

AMLD6 (Anti-Money Laundering Directive 6, UE 2021)

Renforce les obligations de surveillance des transactions suspectes. Introduit la notion de responsabilité pénale pour les entités ne disposant pas de contrôles adéquats. Le scénario "Black Swan" (fraude ×5) dans le stress testing répond à cette exigence.

Bâle III / IV (Comité de Bâle sur le contrôle bancaire)

Accords internationaux imposant aux banques de maintenir des exigences en capital calculées à partir de modèles de risque validés et résistants aux stress scenarios.


📦 Dépendances

Obligatoires

Package Version testée Usage
pandas ≥ 1.5 Manipulation des données
numpy ≥ 1.23 Calculs numériques
scikit-learn ≥ 1.2 Modèles, métriques, CV
matplotlib ≥ 3.6 Visualisations
scipy ≥ 1.9 Tests statistiques (KS, chi², etc.)

Optionnelles

Package Version testée Usage
shap ≥ 0.41 SHAP values pour l'explainabilité
networkx ≥ 3.0 Graph Anomaly Detection
openpyxl ≥ 3.1 Génération du dataset Excel

❓ FAQ

Q : Puis-je utiliser un modèle non-sklearn (XGBoost, LightGBM, CatBoost, PyTorch) ?

Oui. La plupart des méthodes n'ont besoin que de y_proba (un array numpy de probabilités). Pour les méthodes qui requièrent un objet modèle (permutation_feature_importance, cross_validate, walk_forward_backtest), votre modèle doit exposer les méthodes .fit(X, y) et .predict_proba(X), ce que font nativement XGBoost, LightGBM et CatBoost avec leur API sklearn.

Q : Le framework fonctionne-t-il pour la détection d'anomalies non-supervisée ?

Partiellement. Les métriques basées sur les labels (y_true) ne sont pas applicables. En revanche, les modules Benford, Graph Anomaly Detection, et Mahalanobis/Isolation Forest fonctionnent sans labels et peuvent être utilisés standalone.

Q : Comment adapter les seuils réglementaires à mon contexte ?

Les seuils PSI (0.10/0.25), ECE (0.05), disparate impact (0.80), etc. sont des valeurs standard de l'industrie. Ils peuvent être ajustés selon les exigences spécifiques de votre régulateur. Documentez tout ajustement dans votre rapport de validation.

Q : Le rapport HTML est-il partageable directement ?

Oui. Le HTML généré est entièrement autonome : toutes les images sont encodées en base64 et intégrées dans le fichier. Il peut être envoyé par email, partagé sur un drive, ou publié comme page web statique sans dépendance externe.

Q : Quelle taille de jeu de test est recommandée ?

Pour des IC bootstrap fiables, un minimum de 5 000 observations dans le jeu de test est recommandé, dont au moins 200 fraudes. En dessous, les IC seront très larges et les métriques peu fiables.

Q : Comment interpréter un H-measure très différent de l'AUC ?

L'AUC suppose implicitement une distribution uniforme des coûts de mauvaise classification. Le H-measure utilise une distribution Beta(2,2) sur les coûts, ce qui est plus réaliste. Si H-measure << AUC, votre modèle performe bien en moyenne mais mal aux seuils de décision où les coûts sont les plus asymétriques — c'est souvent le cas des modèles surajustés sur les cas faciles.


📄 Licence

MIT License — libre d'utilisation, modification et distribution avec attribution.


FraudModelValidatorV2 — Validation rigoureuse pour des décisions de confiance.

About

50 000 transactions (48 000 légitimes + 2 000 fraudes) avec 30 variables, organisées en 4 typologies de fraude réalistes. Données générées par LLM (Claude/Anthropic)

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors