A machine learning pipeline for detecting fraudulent bank transactions — covering SQL-based investigation, class imbalance handling (SMOTE), model comparison, and an interactive Tableau dashboard.
Built by: Xintian (Cindy) Shi · LinkedIn · GitHub
Card fraud costs the global banking industry over $30 billion annually. Detecting it is hard: fraud is rare (0.17% of transactions), patterns shift constantly, and false positives — blocking legitimate customers — erode trust. This project builds a detection pipeline that balances precision and recall with that tradeoff in mind.
Credit Card Fraud Detection — ULB Machine Learning Group
- 284,807 real European bank transactions over two days
- 492 confirmed fraud cases (0.172% of total)
- Features:
Time,Amount, 28 PCA-anonymized components (V1–V28),Class
- Fraud peaks at 2am–4am — 2am has a 1.71% fraud rate vs. 0.17% average; consistent with automated card-testing attacks when human review is minimal
- 13.8% of fraud transactions are under $1.00 — a known card-testing pattern where fraudsters verify stolen cards with micro-charges before making large purchases
- Average fraud amount: $122.21 vs. $88.29 for legitimate — fraudsters target higher-value transactions once a card is confirmed active
- V14, V10, V12 are the strongest fraud signal features in the PCA space (confirmed by both correlation analysis and Random Forest feature importance)
| Step | Method |
|---|---|
| Storage & investigation | SQLite + 7 analytical SQL queries |
| EDA | pandas, NumPy, matplotlib, seaborn |
| Class imbalance | SMOTE — training set balanced to 50/50 (228K rows) |
| Baseline model | Logistic Regression |
| Main model | Random Forest (100 estimators) |
| Evaluation | Precision, Recall, F1, AUC-ROC, Precision-Recall Curve |
| Dashboard | Tableau Public |
| Model | Precision | Recall | F1 | AUC-ROC | PR-AUC |
|---|---|---|---|---|---|
| Logistic Regression | 0.056 | 0.918 | 0.105 | 0.971 | 0.728 |
| Random Forest (tuned) | 0.842 | 0.816 | 0.829 | 0.967 | 0.870 |
| XGBoost | 0.697 | 0.867 | 0.773 | 0.979 | 0.871 |
Logistic Regression catches nearly all fraud (91.8% recall) but floods analysts with false positives — 94% of its fraud flags are wrong. Random Forest achieves the best precision (84.2%) — 5 out of 6 flagged transactions are genuine fraud. XGBoost leads on AUC-ROC and PR-AUC, making it the strongest overall ranker.
Top predictive features: V14, V4, V10, V17, V12 — consistent across both tree models
At a 95% precision threshold on the held-out test set (56,962 transactions, XGBoost):
| Value | |
|---|---|
| Transactions flagged | 82 |
| True fraud caught | 78 (79.6% recall) |
| False alarms | 4 |
| Fraud missed | 20 |
| Estimated loss prevented | $9,532.38 |
At 95% precision the model blocks only 4 legitimate cards to catch 78 fraud cases — a 19.5:1 true-positive ratio. Lowering the threshold to 80% precision catches more fraud at the cost of more false alarms; the Precision-Recall curve in 03_models.ipynb shows the full tradeoff.
# 1. Clone repo and set up environment
git clone https://github.com/SXT2918/fraud-detection.git
cd fraud-detection
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
# 2. Download dataset
# Go to kaggle.com/datasets/mlg-ulb/creditcardfraud
# Unzip archive.zip and place creditcard.csv inside data/
# 3. Build SQLite database
python src/database.py
# 4. Run SQL investigation
sqlite3 data/fraud.db < sql/explore.sql
# 5. Open notebooks in order
jupyter notebook notebooks/fraud-detection/
├── data/ # creditcard.csv + fraud.db (gitignored)
├── sql/
│ └── explore.sql # 7 investigative SQL queries
├── notebooks/
│ ├── 01_eda.ipynb # EDA: class imbalance, amount, time, correlations
│ ├── 02_features.ipynb # SMOTE, scaling, train/test split
│ └── 03_models.ipynb # Logistic Regression, Random Forest, PR curves
├── src/
│ └── database.py # Loads CSV into SQLite, creates hourly_summary view
├── tableau/ # Exported PNGs + CSVs for dashboard
└── requirements.txt
Python · pandas · NumPy · scikit-learn · imbalanced-learn · SQLite · matplotlib · seaborn · Tableau Public · Jupyter