File size: 1,476 Bytes
99bc19c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
"""
Explainability via SHAP — a compliance requirement, not a nice-to-have.

Fraud models in finance fall under model-risk-management regimes (e.g. SR 11-7)
that demand every automated decline be explainable. SHAP gives both:
  - global feature importance (which signals drive fraud overall)
  - per-transaction attributions (why THIS txn was flagged) for adverse-action
    notices and analyst review.

TreeExplainer is exact and fast for LightGBM/XGBoost.
"""
from __future__ import annotations

import numpy as np


def compute_shap(model, X_sample):
    """Return (shap_values_for_positive_class, explainer)."""
    import shap
    explainer = shap.TreeExplainer(model)
    sv = explainer.shap_values(X_sample)
    # Newer SHAP returns a single array for binary LightGBM; older returns a list
    if isinstance(sv, list):
        sv = sv[1]
    return np.asarray(sv), explainer


def global_importance(shap_values, feature_names, top_k: int = 20):
    """Mean absolute SHAP per feature, sorted descending."""
    mean_abs = np.abs(shap_values).mean(axis=0)
    order = np.argsort(mean_abs)[::-1][:top_k]
    return [(feature_names[i], float(mean_abs[i])) for i in order]


def explain_transaction(shap_values, feature_names, row_idx: int, top_k: int = 6):
    """Top contributing features (signed) for a single transaction."""
    row = shap_values[row_idx]
    order = np.argsort(np.abs(row))[::-1][:top_k]
    return [(feature_names[i], float(row[i])) for i in order]