Skip to content
← All work

01 · Credit scorecard · ML

Credit Scorecard Engine

Two WOE scorecards on 307,511 real applications, one with bureau data and one without. The interesting part is where they disagree.

Holdout AUC, bureau scorecard
0.737
Gini
0.473
Holdout in the inclusion gap
14.7%
Illustrative missed lending
≈R4.9bn

Holdout default rate by agreement segment

From the repo README, seed 42 holdout. Hover a bar for the rate.

Problem

A bureau scorecard can only judge people the bureau knows. Thin-file applicants get rejected or referred by default, and nobody measures how many of them would have paid. I wanted that number, on real data, from a model a regulator would accept.

Approach

  1. 01Home Credit Default Risk data, 307,511 applications. Sixteen features picked from 122 raw columns. Missing EXT_SOURCE values get their own WOE bin instead of imputation, because missingness carries signal.
  2. 02WOE/IV binning and points scaling written from scratch. No scorecardpy. Scores run 300 to 850 with PDO 20 and base 600, and accept/refer/reject cutoffs come from score percentiles.
  3. 03Two instances of the same pipeline class. Traditional uses 16 features including bureau scores. Alternative uses 10 non-bureau features. An XGBoost benchmark with SHAP runs on the combined features but never makes decisions.
  4. 04FastAPI backend on Render, React dashboard on Vercel. Each applicant gets two scores, two decisions, and a variable-level explanation.

Results

Traditional scorecard: AUC 0.737, Gini 0.473, KS 0.355. Alternative: AUC 0.631, Gini 0.261, KS 0.203. XGBoost reached AUC 0.753, but the scorecard stays the decision model because the NCA wants decisions you can explain.

14.7% of the holdout (9,021 applicants) sit in the inclusion gap: the bureau model rejects or refers them, the alternative model accepts. They default at 12.1%. That is 3.4x agreed accepts (3.6%) and well under agreed rejects (20.8%). The bureau model is partly right about them, not entirely.

The reverse group, bureau accepts and alternative rejects, defaults at 5.1%. Neither model has a monopoly on the truth.

Next

Reject inference on the through-the-door population, vintage stability tests, and a South African bureau sample instead of Home Credit.