← AI Engineering
Classical Machine Learning · Classification

Credit Card Fraud Detection with Explainability

A classification case study under extreme class imbalance (0.17% fraud rate): comparing correction strategies across two model families, tuning the decision threshold, and explaining individual predictions with SHAP.

Python scikit-learn imbalanced-learn SHAP Random Forest

The problem

Can a model reliably catch fraudulent credit card transactions when they make up just 0.17% of all transactions — and can it explain, transaction by transaction, why it flagged what it flagged? 284,807 real transactions, 492 of them confirmed fraud, were used to find out.

Key results

94.3%
Precision (final model)
84.7%
Recall (final model)
0.17%
Fraud rate in the data
5
Features drive most decisions

Why accuracy is the wrong metric here

A model that always predicts "not fraud" — without looking at any data — would be right 99.83% of the time. That number looks excellent and means nothing: the model would never catch a single fraud. This is why the entire project is evaluated on precision and recall rather than accuracy, and specifically on the Precision-Recall AUC, which stays meaningful even under this level of imbalance (unlike the more commonly used ROC-AUC).

Comparing imbalance-handling strategies, honestly

Two model families were tested under three strategies: no correction, class weighting, and SMOTE (synthetic minority oversampling). Both correction techniques were applied strictly to the training data only — the test set always reflects the true, real-world imbalance.

Model / StrategyPrecisionRecallF1
Logistic Regression — Baseline0.8310.6530.731
Logistic Regression — Class Weighted0.0550.9080.105
Logistic Regression — SMOTE0.0540.9180.102
Random Forest — Baseline0.9410.8160.874
Random Forest — Class Weighted0.9610.7550.846
Random Forest — SMOTE0.8890.8160.851

On the linear model, both correction techniques produced nearly identical, aggressive results — recall shot up but precision collapsed to roughly 1-in-18 flagged transactions being real fraud. On Random Forest, the same techniques diverged meaningfully instead, and neither clearly beat the uncorrected baseline. The simplest option — no resampling — was carried forward as the final model, avoiding complexity that wasn't clearly earning its keep.

A nearly free improvement: threshold tuning

The default 0.5 decision threshold is just a convention. Scanning the full precision-recall curve of the final model found a better operating point at 0.44 — improving both precision and recall at once, rather than trading one for the other.

Precision rose from 94.2% to 94.3% and recall rose from 82.7% to 84.7% simply by moving the decision threshold — no retraining required.

Explaining individual predictions with SHAP

Knowing which features matter on average isn't enough to justify flagging one specific transaction. SHAP attributes each prediction to the individual contribution of every feature, for that exact case.

Five anonymized features — V17, V14, V12, V10, and V16 — consistently dominate the model's fraud predictions, both globally and in individual case breakdowns. For one transaction flagged at 95.5% fraud probability, these five features alone accounted for the large majority of the shift away from the dataset's baseline fraud rate, with the remaining 25 features contributing comparatively little.

SHAP summary plot showing V17, V14, V12, and V10 as the most influential features for fraud predictions
Global feature impact: V17, V14, V12, and V10 dominate fraud predictions across the dataset.
SHAP waterfall plot breaking down a single fraud prediction feature by feature
A single flagged transaction (95.5% fraud probability), explained feature by feature.

Tools used

Python Pandas scikit-learn imbalanced-learn SHAP Matplotlib