Skip to content

Latest commit

 

History

16 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

veritas-flag

"Veritas" is Latin for truth. This project is about finding it in transaction data.

A real-time fraud detection system built from scratch. 284,807 credit card transactions. 492 of them fraud. The model's job is to find those 492 without crying wolf on the other 284,315.

This is not a tutorial project, but a full pipeline: raw data in, fraud score out, live API running. Built because I wanted to understand how these systems actually work, not just how they look in a notebook.


What this is

A machine learning pipeline that scores credit card transactions for fraud probability in real time. You send it a transaction. It tells you whether to be worried.

Under the hood: XGBoost trained on PCA-transformed transaction features, SMOTE to handle the severe class imbalance, SHAP to explain every decision, and a FastAPI service that responds in under 100ms.

The dataset is the UCI Credit Card Fraud Detection dataset, one of the most studied fraud datasets in existence. 0.17% of transactions are fraud. That tiny number is where all the interesting problems live


Why I built this

False negatives let fraud through. False positives block real people from their money. Both are failures, and they pull in opposite directions.

I wanted to build something that takes that tension seriously. Not just "maximize accuracy" (useless on imbalanced data) but: what is the right metric, what is the right threshold, and how do you explain the decision to a human analyst who has to act on it?

That is what this project is about.


Architecture

creditcard.csv
284,807 transactions
492 fraud cases (0.17%)
        |
        v
+---------------------+
|   preprocess.py     |  Drop Time, standardize Amount,
|                     |  stratified 80/20 split
+--------+------------+
         |
         v
+---------------------+
|   SMOTE             |  Synthetic oversampling on training set only.
|                     |  Never touches the test set. No leakage.
+--------+------------+
         |
         v
+---------------------+
|   XGBoost           |  Early stopping on PR-AUC.
|                     |  scale_pos_weight for extra imbalance correction.
+--------+------------+
         |
    +----+----+
    v         v
Evaluate    FastAPI
SHAP +      /predict
metrics     endpoint


Results

Trained on the standard UCI Credit Card Fraud dataset (284,807 transactions, 492 fraud cases, 0.17%). SMOTE is applied only to the training set, so these numbers reflect performance on the real, untouched imbalance, not on synthetically balanced test data.

Metric Score
ROC-AUC 0.9768
PR-AUC 0.8604
Optimal threshold 0.9915 (F1 = 0.8492)
Precision (fraud) 0.94
Recall (fraud) 0.78

Confusion Matrix Precision-Recall Curve

Out of 56,962 test transactions (98 of them real fraud), the model caught 76 and missed 22, at the cost of wrongly flagging just 5 legitimate transactions out of 56,864. The PR curve shows why: precision stays near 1.0 out to roughly 60% recall, then degrades in stages rather than falling off a cliff. The model is highly confident on most fraud cases, and only trades away precision to catch the hardest remaining ones.


The decisions that matter

Why PR-AUC and not ROC-AUC

ROC-AUC looks great on fraud data because getting the negatives right is easy when 99.83% of transactions are legitimate. PR-AUC only cares about how well you find the fraud. It is harder to game and more honest about what the model is actually doing.

Why SMOTE plus scale_pos_weight

SMOTE resamples the training set to 50/50 before training starts. scale_pos_weight is computed from that already balanced set, so in this run it comes out to exactly 1.0. It is not adding a second layer of correction. It is confirming the first one worked. I originally framed this as two layers stacking together. The actual numbers showed SMOTE was doing all the work on its own, and that is a more honest thing to say about it.

Why threshold tuning

The default 0.5 threshold is almost never right for imbalanced data. This pipeline finds the threshold that maximizes F1 on the validation set. For this run it lands at 0.9915, meaning the model only flags a transaction as fraud when it is over 99% confident. That is not caution by accident. At ROC-AUC 0.98, fraud and legit scores are already well separated, so pushing the bar that high still catches 76 of 98 fraud cases while wrongly flagging only 5 out of 56,864 legitimate ones.

Why SHAP

Because "the model said so" is not good enough. Every prediction gets decomposed into per-feature contributions. V14 and V4 are the two features that matter most, and they push in opposite directions: low V14 pulls toward fraud, high V4 does the same. That is what a fraud analyst actually needs to investigate, not just a single confidence score.

SHAP Feature Importance SHAP Beeswarm


Tech stack

What How
Model XGBoost 2.0
Imbalance SMOTE via imbalanced-learn
Explainability SHAP TreeExplainer
API FastAPI + Uvicorn
Data pandas, numpy, scikit-learn
Serialization XGBoost native JSON

Setup

Mac users, install this first (XGBoost needs it and macOS does not ship it by default):

brew install libomp

Clone and install:

git clone https://github.com/yanastaciocubas/veritas-flag.git
cd veritas-flag
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

Get the data (one command, no account needed):

mkdir -p data && cd data
curl -o creditcard.csv https://storage.googleapis.com/download.tensorflow.org/data/creditcard.csv
cd ..

Train and evaluate:

cd src
python train.py

This saves the model to models/ and generates all four plots above into outputs/plots/.

Run the API:

cd ../api
uvicorn app:app --reload --port 8000

Open http://localhost:8000/docs for the interactive Swagger UI. Try /predict with a sample transaction and watch a real fraud score come back.

About

Real-time credit card fraud detection. XGBoost + SMOTE + SHAP + FastAPI. 284,807 transactions, 492 needles in the haystack.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages