End-to-end deep learning project β 590,540 real IEEE-CIS banking transactions, PySpark distributed sequence engineering, 2-layer GRU with custom Attention mechanism, attention weight visualisation, and ZAR business impact analysis. Extends the
fraud-detection-mlXGBoost project from point-in-time to sequential fraud detection.
The fraud-detection-ml project scores one transaction at a time β a point-in-time
decision using tabular features. This project scores the entire customer behavioural
sequence β capturing fraud patterns that only emerge over time:
Card testing pattern (invisible to XGBoost):
T1: R12 Groceries β fraudster tests if card is active
T2: R45 Restaurant β small legitimate-looking purchase
T3: R890 Electronics β escalating amount
T4: R8,500 Forex β large fraudulent withdrawal
β
GRU sees this sequence shape β XGBoost only sees T4
GRU maintains a hidden state β a memory that carries information forward through the transaction sequence. The Attention layer then reveals which specific transactions in the sequence most influenced the fraud prediction.
A Gated Recurrent Unit (GRU) is a recurrent neural network that maintains a memory (hidden state) across a sequence of transactions. At each timestep it decides what to remember and what to forget using two learned gates: For each transaction timestep t: h(t-1) β Memory from all prior transactions
-
RESET GATE: sigmoid(Wr Γ [h(t-1), x(t)]) Determines how much of the past to forget. (0.0 = forget all history, 1.0 = keep all history)
-
UPDATE GATE: sigmoid(Wu Γ [h(t-1), x(t)]) Determines how much past vs new information to keep.
-
NEW HIDDEN STATE h(t): The updated memory passed to the next transaction timestep. Why GRU over a stacked LSTM for this dataset:
| Property | Stacked LSTM | 2-Layer GRU |
|---|---|---|
| Gates per unit | 3 (forget, input, output) | 2 (reset, update) |
| Parameters | Higher (~25% more) | Fewer β faster training |
| Sequence length suitability | Very long (500+ steps) | Short-medium (10β50 steps) |
| Overfitting risk on small datasets | Higher | Lower |
| Training stability | Prone to exploding gradients | More stable with clipnorm |
| Our median sequence length | 4 transactions | β GRU optimal |
The EDA (Section 2.4) confirmed the median card has only 4 transactions and 90.9% of cards have fewer than 50 transactions. A stacked LSTM with 3 gates per unit would introduce unnecessary parameters and overfitting risk on sequences this short. GRU's simpler 2-gate architecture is precisely calibrated for this sequence length regime β and the results confirm it: ROC-AUC = 0.8611, PR-AUC = 0.6671 (3.70Γ above random baseline of 0.1805).
| Property | Value |
|---|---|
| Dataset | 590,540 IEEE-CIS real banking transactions |
| Transaction fraud rate | 3.499% (real-world 28:1 imbalance) |
| Unique cards | 13,553 |
| Sequences built | 8,419 (cards with β₯ 3 transactions) |
| Sequence fraud rate | 18.03% (cards with any fraudulent transaction) |
| Sequence shape | (8,419 Γ 50 timesteps Γ 30 features) |
| Architecture | 2-Layer GRU + Bahdanau Attention |
| Test ROC-AUC | 0.8611 |
| Test PR-AUC | 0.6671 (vs random 0.1805 β 3.70Γ better) |
| Optimal threshold | 0.08 |
| Net financial benefit | R1,670,000+ per test set |
| MLflow model | ieee-cis-gru-attention-v1 / Version 1 |
590,540 IEEE-CIS Transactions
β
βΌ PySpark β Window functions, distributed rolling features
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Sequence Engineering β
β Per-card transaction histories sorted by time β
β Rolling amount stats Β· velocity Β· time gaps β
β Cyclical time encoding Β· categorical encoding β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β (n_cards, seq_len=50, n_features) numpy arrays
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β 2-Layer GRU + Bahdanau Attention β
β β
β Input (50, n_features) β
β β Masking (ignore zero-padded timesteps) β
β β GRU(128, return_sequences=True) β
β β BatchNorm + Dropout(0.3) β
β β GRU(64, return_sequences=True) β
β β BatchNorm + Dropout(0.3) β
β β Attention (learns which timesteps matter) β
β β Dense(32, relu) + Dropout β
β β Dense(1, sigmoid) β fraud probability β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Evaluation & Explainability β
β ROC-AUC Β· PR-AUC Β· F1 Β· Confusion matrix β
β Attention heatmaps β which transactions drove score β
β ZAR threshold optimisation Β· MLflow registration β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# 1. Download IEEE-CIS dataset from Kaggle
# https://www.kaggle.com/competitions/ieee-fraud-detection/data
# Download: train_transaction.csv + train_identity.csv
# Place in: data/raw/
# 2. Install dependencies
pip install -r requirements.txt
# 3. Run preprocessing (builds sequences from raw CSVs)
python src/data/preprocess.py
# 4. Launch Jupyter
jupyter lab notebooks/ieee_fraud_gru.ipynb
# 5. Run tests
pytest tests/ -v
# 6. View MLflow experiment
mlflow ui # β http://localhost:5000
β οΈ Windows + PySpark: Requires Java 17 asJAVA_HOMEandPYSPARK_PYTHONset to your Python 3.11 executable.
| Section | Description | Key output |
|---|---|---|
| 0 | Environment setup | All imports verified |
| 1 | PySpark loading | 590,540 rows Β· 434 columns Β· fraud rate 3.499% |
| 2.1 | Class distribution | 28:1 imbalance Β· PR-AUC chosen as primary metric |
| 2.2 | Amount distribution | Fraud heavier right tail Β· log-transform justified |
| 2.3 | Fraud by product code | Product-level fraud rate variation |
| 2.4 | Sequence lengths | Median=4 Β· 90.9% covered by seq_len=50 |
| 3.1 | Temporal features | Cyclical encoding Β· is_night Β· is_weekend |
| 3.2 | Categorical encoding | StringIndexer via SparkML Pipeline |
| 3.3 | Window features | Rolling stats Β· velocity Β· time gaps per card |
| 4.1 | Sequence features | 30 features selected from 434 columns |
| 4.2 | Sequence construction | 8,419 sequences Β· (8419 Γ 50 Γ 30) Β· 18.03% fraud |
| 4.3 | Split + normalisation | 70/15/15 stratified Β· train-only normalisation |
| 5.1 | Model architecture | 2-Layer GRU + Attention Β· ~85k parameters |
| 5.2 | Training | 50 epochs Β· EarlyStopping Β· ReduceLROnPlateau |
| 5.3 | Training history | PR-AUC and loss curves β healthy convergence |
| 6.1 | Evaluation metrics | ROC-AUC=0.8611 Β· PR-AUC=0.6671 |
| 6.2 | ROC & PR curves | Strong early climb Β· 3.70Γ above random |
| 6.3 | Confusion matrix | Fraud recall strong at default threshold |
| 7.1 | Attention extraction | (1000, 50) attention weight matrix |
| 7.2 | Local β Card #4 | P=0.976 Β· peak timestep 24 Β· mid-sequence cluster |
| 7.3 | Average attention | Fraud sequences attend more to recent transactions |
| 8 | Business impact | Optimal threshold=0.08 Β· net benefit R1.67M+ |
| 9 | MLflow logging | ieee-cis-gru-attention-v1 Version 1 registered |
| 10 | Final summary | Complete results + four-project portfolio context |
Source: IEEE-CIS Fraud Detection (Kaggle)
Transactions: 590,540 rows Γ 394 columns
Identity: 144,233 rows Γ 41 columns
Fraud rate: ~3.5% (real-world imbalanced)
Features: Transaction amounts, card details, device info,
Vesta-engineered V/C/D features, email domains
β οΈ The dataset is not committed to this repo β download from Kaggle and placetrain_transaction.csvandtrain_identity.csvindata/raw/.
class AttentionLayer(layers.Layer):
"""
Bahdanau-style soft attention over GRU hidden states.
For each timestep h_t:
e_t = tanh(W_a Γ h_t + b_a) β score
Ξ±_t = softmax(e_t) β attention weight
c = Ξ£ Ξ±_t Γ h_t β context vector
Returns: context_vector + attention_weights
The weights show WHICH transactions drove the fraud score.
"""Attention weights serve as the RNN equivalent of SHAP β providing per-timestep explanations that satisfy FSCA regulatory requirements for explainable automated decisions.
| Component | Technology |
|---|---|
| Distributed processing | PySpark 3.5 (Window functions, rolling features) |
| Deep learning | TensorFlow 2.x / Keras |
| Architecture | 2-Layer GRU + Custom Bahdanau Attention |
| Imbalance | class_weight balanced |
| Experiment tracking | MLflow 2.10 |
| Visualisation | matplotlib, seaborn |
| Testing | pytest |
| CI/CD | GitHub Actions |
ieee-fraud-gru/
β
βββ π notebooks/
β βββ ieee_fraud_gru.ipynb # Main notebook β 10 sections
β
βββ π src/
β βββ data/
β β βββ preprocess.py # PySpark sequence engineering pipeline
β βββ models/
β β βββ gru_attention.py # GRU + Attention model + callbacks
β βββ evaluation/
β βββ evaluate.py # Metrics + attention visualisation
β
βββ π data/
β βββ raw/ # Place Kaggle CSVs here (not committed)
β βββ train_transaction.csv
β βββ train_identity.csv
β
βββ π reports/
β βββ figures/ # Generated charts (not committed)
β
βββ π tests/
β βββ test_pipeline.py # 17 unit tests
β
βββ π .github/
β βββ workflows/
β βββ ci.yml # GitHub Actions
β
βββ .gitignore
βββ requirements.txt
βββ README.md
| # | Project | What it demonstrates |
|---|---|---|
| 1 | idm-debt-pipeline |
Medallion batch pipeline β ADF, Databricks, ADLS Gen2 |
| 2 | nedbank-streaming-pipeline |
Real-time ELT β Kafka, PySpark Streaming, Delta MERGE INTO |
| 3 | fraud-detection-ml |
4-model shootout β XGBoost vs RF vs LR vs MLP, SHAP, MLflow |
| 4 | ieee-fraud-gru β This |
Sequential fraud detection β GRU + Attention, PySpark sequences |
Projects 3 and 4 form a complementary fraud detection system:
- Project 3 (XGBoost): Scores individual transactions at point-in-time
- Project 4 (GRU): Scores entire customer behavioural sequences
Together they provide defence-in-depth β catching both isolated anomalous transactions AND sequential fraud patterns.
MIT