Probability-of-default (PD) scoring on 50,000+ real Lending Club loans, from multi-format data wrangling through a stacked XGBoost + Logistic Regression model, credit-scorecard scaling, and stakeholder-facing Tableau dashboards.
This project builds and validates a credit risk scoring model that estimates the probability that a borrower will default, then translates that probability into a familiar 300–850 credit score and an approve/decline decision. It is designed as a realistic, reproducible analytics workflow:
- Data: the public Lending Club loan book (2007–2018) — a sample of resolved loans is staged across four file formats to mirror a real multi-source ingestion layer.
- Modelling: a stacked ensemble of XGBoost and Logistic Regression with a logistic meta-learner, trained under strict train / validation / test splits.
- Validation: the credit-industry diagnostics — AUC-ROC, KS statistic, Gini, calibration, and PSI — plus WOE/IV feature screening and a VIF multicollinearity check.
- Delivery: an interactive Tableau Public dashboard suite plus the aggregated extracts that back it, letting stakeholders answer prescriptive questions about approval thresholds and portfolio exposure.
Kaggle (Lending Club)
│ fetch_data.py
▼
data/raw/ ──► CSV + JSON + Excel + Parquet (multi-format sources)
│ load_data.py (read each format, join on loan_id)
▼
data/interim/loans_merged.parquet
│ make_dataset.py (parse % / text, missing-value & outlier treatment, de-dup, target)
▼
data/processed/loans_model_ready.parquet
│ build_features.py (WOE/IV ranking, feature selection, VIF, 3-way split)
▼
train / valid / test ──► train_model.py (stacked XGBoost + LogReg + MLflow)
│ │
│ ▼ evaluate.py (AUC/KS/Gini/PSI + figures)
│ ▼ predict_model.py (PD → 300-850 scorecard, decisioning)
▼
tableau/extracts/*.csv ◄── build_tableau_extracts.py ──► Tableau dashboards
Out-of-sample performance on the held-out test set (stacked model):
| Model | AUC-ROC | KS | Gini |
|---|---|---|---|
| Logistic Regression | 0.7085 | 0.3152 | 0.4169 |
| XGBoost | 0.7104 | 0.3171 | 0.4208 |
| Stacked (final) | 0.7109 | 0.3198 | 0.4218 |
Population Stability Index (validation → test) = 0.0008 (< 0.10 ⇒ stable). Decile gains: the riskiest 10% of loans default at 44.4% vs 4.7% for the safest decile. At a PD ≤ 0.20 cutoff, 59.8% of applications are approved with an 11.4% default rate vs 19.7% book-wide.
Trained on 60,000 resolved Lending Club loans (book default rate 19.7%), strict 64 / 16 / 20 train / validation / test split, stratified on the target.
| Diagnostic | Figure |
|---|---|
| ROC curves (all models) | reports/figures/roc_curves_test.png |
| KS separation | reports/figures/ks_curve_test.png |
| Calibration | reports/figures/calibration_test.png |
| Gains by risk decile | reports/figures/gains_by_decile_test.png |
| Feature importance | reports/figures/feature_importance.png |
| Default rate by segment | reports/figures/eda_default_by_grade.png |
🔗 Explore the interactive dashboards on Tableau Public — risk distribution, borrower-segment risk, KPI trends, the approval-threshold simulator, and portfolio exposure & expected loss.
Full metrics are written to reports/metrics.json; the
model card lives in reports/model_card.md.
# 0. Clone and create an environment
git clone https://github.com/Devisri-B/Credit-Risk-Scoring-Model.git
cd Credit-Risk-Scoring-Model
python -m venv .venv && source .venv/bin/activate
# 1. Install
make setup # or: pip install -r requirements.txt && pip install -e .
# 2. Add Kaggle API credentials (needed once to download the data)
# kaggle.com -> Settings -> Create New API Token -> ~/.kaggle/kaggle.json
chmod 600 ~/.kaggle/kaggle.json
# 3. Run the full pipeline (download -> clean -> model -> evaluate -> dashboards)
python run_pipeline.pyRun a single stage with the Makefile: make data, make features, make train,
make evaluate, make score, make tableau, make test.
Inspect experiments with make mlflow-ui.
Credit-Risk-Scoring-Model/
├── config/config.yaml # all tunables (paths, model params, scorecard)
├── data/ # raw / interim / processed / external (git-ignored)
├── sql/ # schema, feature-engineering & analysis queries
├── src/
│ ├── config.py # config loader
│ ├── data/ # fetch (Kaggle) · load (multi-format) · clean
│ ├── features/ # WOE/IV · selection · VIF · train/valid/test split
│ ├── models/ # train (stack) · evaluate · scorecard/predict
│ ├── visualization/ # EDA figures · Tableau extracts
│ └── utils/ # metrics (AUC/KS/Gini/PSI), logging
├── notebooks/ # EDA · feature engineering · modelling walkthroughs
├── tableau/ # dashboard extracts + workbook guide
├── reports/ # metrics.json, IV/VIF reports, figures, model card
├── tests/ # offline unit tests (pytest)
├── run_pipeline.py · Makefile · pyproject.toml
- Multi-format ingestion — the loan book is split into CSV, JSON, Excel and
Parquet sources and rejoined on
loan_id, exercising heterogeneous I/O. - Wrangling — parses Lending Club's text/percent quirks (
"36 months","13.56%","10+ years"), treats missing values (median / indicator flags), winsorises outliers (IQR), and de-duplicates. - Feature screening — Information Value ranks predictors; Weight-of-Evidence re-expresses them on a log-odds scale; VIF flags multicollinearity for the logistic leg (assumption verification).
- Stacked model — XGBoost (non-linear interactions) + Logistic Regression (monotone, interpretable) combined by a logistic meta-learner; XGBoost tree count is chosen by early stopping on the validation set.
- Scorecard — PD is scaled to 300–850 via points-to-double-the-odds (PDO), enabling intuitive cutoffs and portfolio segmentation.
- Monitoring — PSI quantifies score drift between validation and test.
Python · pandas · NumPy · scikit-learn · XGBoost · statsmodels ·
MLflow · matplotlib / seaborn · SQL · Tableau · pytest
Uses the publicly available Lending Club dataset for educational purposes. The raw data is not redistributed in this repository — it is downloaded on demand via the Kaggle API. Predictions are illustrative and not financial advice.
MIT © 2026 Devisri B