Classification

Fee Default Prediction

Catching fee default in week one instead of week ten.

Headline stat

0.70 recall on the default class, from gradient boosting.

The problem

I am a school administrator, and I have a habit of trying to automate the parts of my job that feel like they should not need a human. Fee default was the loudest of those.

About one in four term level fee obligations at the school went partly or fully unpaid. That is not an abstraction when you are the person it lands on. It shows up as delayed teacher salaries and deferred maintenance. And we almost always found out too late, once the term was already underway and the money was already not there.

The information to see it coming was sitting in our own records the whole time. Nobody had ever looked at it that way.

The approach

The dataset is 2,280 term level payment records covering three academic years, built from routine administrative invoices and payment history. Fourteen predictors, across payment behaviour, policy compliance, fee structure, and student characteristics.

I started with logistic regression, then widened it into a comparative study across four classifiers (logistic regression, decision tree, random forest, and gradient boosting) with five fold cross validation. Gradient boosting gave the best recall on the default class, which is the metric that actually matters here. Missing a defaulter costs the school real money. A false alarm costs one awkward conversation.

It is deployed as a Streamlit dashboard over PostgreSQL, containerised with Docker Compose, so an administrator can pull up a student and see their risk without touching a notebook. Every student record was anonymised before any of it left the school.

Gallery

Gallery coming soon

What I learned

The models barely mattered. The features did. Almost all of the predictive power came from getting the right things into the dataset, and once they were there even the simple models did respectably. I had assumed the interesting decisions would be about algorithms, and they were not.

The sharpest lesson was about screening features. Days to first payment had a raw correlation with default of about 0.02, which is essentially nothing, and I would have thrown it out on that basis. In the multivariate model it turned out to be one of the strongest risk signals in the dataset. Judging features one at a time is a good way to discard the useful ones.

The honest limitation is recall. Catching seven defaulters in ten is a real improvement on finding out in week ten, but it is not a solved problem, and the school should know that when it uses the tool. It is there to support the administrator's judgement, not to replace it.

Links

View code