Spaces:
Sleeping
Sleeping
File size: 6,696 Bytes
71c85a4 | 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 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 | # Fraud Detection on PaySim β End-to-End ML Pipeline
A production-style machine learning pipeline that detects fraudulent mobile-money
transactions in the [PaySim synthetic dataset](https://www.kaggle.com/datasets/ealaxi/paysim1)
(~6.3M transactions). The project covers the full lifecycle: data validation,
feature engineering, model training with experiment tracking, and model serving
through both a REST API and a web UI.
> **Focus:** this repo is less about squeezing out the last decimal of accuracy and
> more about doing the *engineering* around a model correctly β no data leakage,
> reproducible training, tracked experiments, saved artifacts, and a real serving layer.
---
## Results
Evaluated on a **chronologically held-out test set** (later time steps the model never
saw during training), so the numbers reflect genuine generalization rather than
memorization.
| Metric | @ threshold 0.50 | @ tuned threshold (0.64) |
|---|---|---|
| **PR-AUC** | **0.90** | 0.90 |
| Precision | 0.83 | 0.95 |
| Recall | 0.84 | 0.79 |
| F1 | 0.83 | 0.87 |
*PR-AUC (area under the precisionβrecall curve) is the headline metric β accuracy is
misleading here because only ~0.2β4% of transactions are fraudulent.*
**Known failure mode:** the model catches `TRANSFER` fraud almost perfectly (>99%
confidence) but is weaker on `CASH_OUT` fraud. In PaySim, fraud is typically a
`TRANSFER` of stolen funds *followed by* a `CASH_OUT` of the same money β the `TRANSFER`
leg carries the obvious "account drained to zero" signature, while the `CASH_OUT` leg
looks much like a legitimate withdrawal. Improving `CASH_OUT` recall (e.g. features
that link a cash-out back to a preceding transfer) is the clearest next modelling step.
> β οΈ **Honesty note:** the tuned threshold (0.64) was selected on the test set, so its
> precision is mildly optimistic. The @0.50 numbers are the trustworthy ones. The test
> window is also more fraud-dense than the training window, so real-world precision at a
> lower fraud base rate would be lower.
---
## Approach
**Avoiding data leakage** β the most common mistake on this dataset:
- **Chronological split** by transaction `step` (train on earlier steps, test on later),
mimicking how a fraud model is used in production: trained on the past, scoring the future.
- The feature scaler is **fit on the training split only** and reused at inference.
- The class-imbalance weight (`pos_weight`) is computed from the **training split only**.
**Feature engineering** (in `src/data/preprocess.py`):
- `errorBalanceOrig` / `errorBalanceDest` β accounting inconsistencies between stated
balances and transaction amounts (the highest-signal engineered features).
- `orig_balance_missing` / `dest_balance_missing` β flags for placeholder-zero balances.
- One-hot encoded transaction type; only `TRANSFER` and `CASH_OUT` are kept, as these
are the only types where fraud occurs in PaySim.
**Model:** a small PyTorch MLP (`FraudMLP`) with BatchNorm and Dropout, trained with
`BCEWithLogitsLoss` weighted for the severe class imbalance.
**Threshold tuning:** instead of a naive 0.5 cutoff, the decision threshold is selected
from the precisionβrecall curve to balance precision and recall (F1-optimal).
---
## Tech stack
| Area | Tools |
|---|---|
| Data / features | pandas, scikit-learn |
| Data validation | Great Expectations |
| Modelling | PyTorch |
| Experiment tracking | MLflow |
| Serving | FastAPI, Gradio, Uvicorn, Pydantic |
---
## Project structure
```
fraud-paysim/
βββ src/
β βββ data/
β β βββ load_data.py # load the raw CSV
β β βββ preprocess.py # cleaning + feature engineering
β βββ features/
β β βββ build_features.py # chronological split, scaling, DataLoaders
β βββ utils/
β β βββ validate_data.py # Great Expectations checks (gate before training)
β βββ models/
β β βββ model.py # FraudMLP architecture
β β βββ train.py # training loop + MLflow logging + test metrics
β β βββ evaluate.py # evaluation + threshold tuning helpers
β βββ app/
β βββ inference.py # shared predict(): raw transaction -> probability
β βββ main.py # FastAPI API (/predict) + Gradio UI (/ui)
βββ scripts/
β βββ run_pipeline.py # end-to-end: load -> validate -> train -> save
βββ requirements.txt
βββ Readme.md
```
---
## Setup
**1. Get the data.** The dataset is not included in the repo (it's ~470 MB). Download
"Synthetic Financial Datasets For Fraud Detection" from
[Kaggle](https://www.kaggle.com/datasets/ealaxi/paysim1) and place the CSV at:
```
fraud-paysim/data/Synthetic_Financial_datasets_log.csv
```
**2. Create a virtual environment and install dependencies:**
```bash
python -m venv .venv
# Windows
.venv\Scripts\activate
# macOS / Linux
source .venv/bin/activate
pip install -r requirements.txt
```
---
## Usage
### Train the model
Runs the full pipeline (load β validate β feature-build β train β evaluate β save artifacts):
```bash
python scripts/run_pipeline.py
```
This logs metrics to MLflow and writes three artifacts to `artifacts/`:
`model.pt` (weights), `scaler.joblib` (fitted scaler), and `metadata.json`
(input dimension + exact feature column order). These three together are what the
serving layer needs to reproduce training-time preprocessing exactly.
Inspect experiments with:
```bash
mlflow ui
```
### Serve the model
```bash
uvicorn src.app.main:app --reload
```
Then open:
- **http://localhost:8000/docs** β interactive REST API (Swagger UI) for the `/predict` endpoint
- **http://localhost:8000/ui** β Gradio web form for manual predictions
**Example request** (a known fraud pattern β full balance transferred out, origin drained to zero):
```json
{
"step": 1,
"type": "TRANSFER",
"amount": 181.0,
"oldbalanceOrg": 181.0,
"newbalanceOrig": 0.0,
"oldbalanceDest": 0.0,
"newbalanceDest": 0.0
}
```
Response:
```json
{ "fraud_probability": 0.9952, "is_fraud": 1 }
```
---
## Design notes
- **Shared inference path.** Both the API and the Gradio UI call the same
`predict()` function, so there is a single source of truth for how a raw transaction
is turned into a prediction β no risk of training/serving skew between the two faces.
- **Raw in, prediction out.** The serving layer accepts *raw* transaction fields and
reconstructs the engineered features internally using the same `preprocess_data`
used in training. Clients never compute features themselves.
---
|