A logistic regression study that estimates the probability of a Fannie Mae single-family loan going into default, built in R with Quarto. The analysis works through roughly 420,000 loan records from the first quarter of 2016 and ends with a formula you can apply to one loan's characteristics to get a default probability.
The output is a formatted HTML article (also exported to PDF) that walks a non-technical reader, whether a homebuyer, lender, or MBS investor, through the data, the modelling, and what the results mean for them.
Fannie Mae buys mortgages from lenders and pools them into mortgage-backed securities. The value of one of those securities depends on how likely the underlying loans are to default, so estimating that risk from a borrower's credit profile and loan terms is useful to several groups at once.
This project:
- Cleans the raw loan-performance data and defines a binary
defaulttarget (1 if the borrower fell 60+ days behind, 0 otherwise). - Explores which borrower and loan features actually separate defaulters from non-defaulters, such as credit score, loan purpose, property type, interest rate, and loan amount.
- Fits a logistic regression and trims it by backward stepwise selection on AIC until only the terms that carry weight remain.
- Reports the final formula and interprets it for homebuyers, banks, and investors.
The final model keeps 13 predictors plus one interaction term between the original loan amount and the last unpaid balance. Its five strongest drivers of default are the last unpaid balance, the original loan amount, credit score, the last interest rate, and whether the property is a second home.
The analysis uses Fannie Mae's Single-Family Loan Performance Data for 30-year, fixed-rate, fully amortizing loans acquired in Q1 2016. The raw extract has 420,436 loans and 75 fields per loan, most of which the script drops.
The CSV is not tracked in this repository because of its size and Fannie Mae's terms of use. To reproduce the report you need to get the data from Fannie Mae and save it as fannie_mae.csv in the project root. The script reads a specific subset of columns, so the file has to contain at least these:
LOAN_ID, CSCORE_MN, ocltv, num_bo, dti, purpose, PROP_TYP, NUM_UNIT, occ_stat, loan_age, orig_rt, orig_amt, orig_trm, oltv, LAST_RT, LAST_UPB, LAST_STAT, F30_DTE, F60_DTE, ORIG_VAL, FTHB_FLG
The default flag is derived from the delinquency date fields (F30_DTE, F60_DTE) and the loan's last status (LAST_STAT). Loans whose eventual status is still unclear are dropped rather than guessed at.
- R 4.x or later
- Quarto (https://quarto.org)
Install the R packages the report uses:
install.packages(c("tidyverse", "knitr", "kableExtra", "gridExtra", "scales"))- Clone the repository.
- Put
fannie_mae.csvin the project root (see "About the data"). - From the project folder, render the document:
quarto render glm-case-study.qmdThis produces glm-case-study.html. You can also open the .qmd in RStudio and click Render.
The header sets echo: false, so code stays hidden in the rendered output and the article reads as prose and figures instead of a code walkthrough. If the CSV is missing, the render stops at the first chunk that tries to read it.
If you just want to read the write-up without installing anything, open the exported PDF (47478667_GLM_CASE_STUDY.pdf).
.
├── glm-case-study.qmd # Quarto source for the report
├── styles.css # Styling for the HTML output
├── images/
│ └── fanniemae-logo.jpg # Cover logo
├── fannie_mae.csv # Loan data (supply this yourself)
└── 47478667_GLM_CASE_STUDY.pdf # Exported report
The response variable is binary, so the analysis uses logistic regression with a logit link. The formula is written in terms of the log-odds of a loan not defaulting, which then converts to a default probability.
Selection ran top-down. It starts with every candidate feature, then drops the weakest ones step by step and keeps the version with the lowest AIC. A bottom-up version (starting from one feature and adding) tended to underfit, so the top-down result was used. Property type came out as insignificant and was left out. Correlated pairs were reduced to one variable each, for example original rate and last rate, with one exception: original amount and last unpaid balance were both kept and combined through an interaction term.
Section 3 of the report has the full formula, the coefficient table, and worked examples that show how changing a single input (loan purpose, credit score, loan amount) moves the predicted probability.
- The model is fit on one quarter of one year. Loans from a different period or rate environment may behave differently.
- Location fields (state, ZIP) and the mortgage seller were left out to keep the model interpretable, even though they could carry signal.
- One result is counterintuitive: a higher last interest rate slightly lowers the predicted default probability when everything else is held fixed. The report flags this as something to verify rather than a conclusion to lean on.
- This began as a coursework case study, so it is written to explain the method to a general audience rather than to run as production scoring code.
The code and write-up are my own work. The underlying loan data belongs to Fannie Mae and is subject to their data terms, which is why it is not included here.
Nadun Chandrabahu