Chapter 4 · Statistical Predictive Models
Section 4.1 · Chapter 4 · Learning Statistics with Python
Statistical Predictive Models
Prof. Xuhu Wan
ISOM, HKUST Business School · 2026 Edition
A lender’s loss on a loan is the product of three things — whether it defaults, how much is still owed when it does, and how little comes back. You will build all three from raw columns, engineer 25 features, and discover how much (and how little) a linear model explains.
LendingClub matches borrowers (debt consolidation, big purchases, medical bills) with funding. The platform underwrites each application with a credit-risk model, sets the rate and term, and either keeps the loan or sells it to investors.
Which statement best describes the platform’s economics?
\[\text{EL} = \underbrace{\text{PD}}_{\text{probability of default}} \times \underbrace{\text{EAD}}_{\text{exposure at default}} \times \underbrace{\text{LGD}}_{\text{loss given default}}\]
Which factor calls for a classification model rather than a regression?
This section builds EAD and LGD by regression. PD waits for §4.3.
The catalog says 20 % of loans are charged off. What does the second line print for Charged Off?
0.2
(8000, 29) — a random sample of the 150 000-loan original. Exactly 80 % Fully Paid, 20 % Charged Off. Every loan here has finished its life, so we know the outcome.
Three ledger columns carry the story: funded_amnt (what was lent), total_rec_prncp (principal repaid), recoveries (cash clawed back after charge-off).
For a Fully Paid loan, what is EAD = (funded_amnt − total_rec_prncp) / funded_amnt?
Among the 1 604 charged-off loans the mean EAD is 0.698 — on average 70 % of the principal was still outstanding — and mean LGD is 0.892: recoveries claw back barely a tenth. The 1e-4 guards the one loan with EADamount = 0. Six loans recovered more than the outstanding principal (late fees, collection interest), which is why the minimum LGD is −0.177 — real ledgers do this, and we keep the raw number.
Raw columns are strings, dates and NaNs. A regression needs numbers with a meaning. You will convert term and employment length, build a credit age, a FICO midpoint, two “time since trouble” clocks, and dummies for three categoricals.
emp_length holds values like "10+ years", "< 1 year", "3 years" and NaN. What does str.extract(r"(\d+)") return for "10+ years" and for "< 1 year"?
['10', '1']
"< 1 year" would extract as 1, so we override it to 0. The 484 loans with no employment record get employment = 0 and a flag employed = 0 — the flag lets the model treat “unknown” differently from “under a year”.
earliest_cr_line is like "Jan-1986". Days from 1 Jan 1986 to 29 Dec 2018 (the data’s end date)?
12050
format="%b-%Y" parses Jan-1986 directly — no guessing, no warnings. Credit histories run from 1 277 to 20 757 days (3.5 to 57 years). install is the monthly instalment as a share of annual income — a burden ratio, not a dollar amount. Three applicants report zero income: dividing by NaN rather than by 0 keeps their ratio missing instead of infinite.
mths_since_last_delinq is NaN for half the loans. What should NaN become?
balance (instalment-loan balance over income) is NaN when the borrower has no instalment loans — there the honest fill is 0.
Grade has 7 levels A–G. Why keep only 6 dummy columns in a regression with an intercept?
Home ownership also has ANY and OTHER (one loan each). We keep OWN, RENT, MORTGAGE as the notebook does — and in §4.2 the VIF will show why that was a trap.
Why permute the rows before taking the first 70 % as training data?
25 features. Six rows are dropped for a missing dti or revol_util — the three zero-income applicants among them. 5 595 / 2 399 loans train/test; of those, 1 146 / 458 defaulted — the EAD and LGD regressions see only these.
R² = 0.192. Longer term (t = 7.5) and higher int_rate (t = 3.5) mean more principal is still outstanding when the loan fails; a heavier instalment install (t = −2.7) means the borrower had paid more down before failing. fico and dti add nothing once the rest are in.
Same 25 features, target LGD. The R² will be roughly:
R² = 0.039, adjusted 0.018. The 150 000-loan notebook found 0.012. LGD is, for practical purposes, a constant near 0.89 — and a model that knows it is a constant is more useful than one that pretends otherwise.
\[R^2_{\text{adj}} = 1 - (1 - R^2)\,\frac{n-1}{n-k-1}, \qquad \text{RMSE} = \sqrt{\tfrac{1}{n}\sum (y_i - \hat y_i)^2}\]
EAD: train adjusted R² 0.174 → test 0.107. LGD: test adjusted R² is negative (−0.080) — worse than predicting the mean. Test RMSE 0.190 for EAD says a typical exposure forecast is off by 19 percentage points of principal.
You have all three factors on the training data. Put them together.
EL = PD × mean EAD × mean LGD, using the default rate in train and the mean EAD and LGD of the defaulted loans train_d. Fix the EL line.
About 12.7 cents per dollar lent — which is why the average interest rate in this book is 13 %.
"< 1 year" → 0, NaN delinquency → 360 (never), missing balance → 0, one dummy dropped per categorical.Next: §4.2 — can interactions and best-subset search raise that 0.107?
Prof. Xuhu Wan · HKUST ISOM · Learning Statistics with Python