A consumer lending application file with a clean binary risk flag looks like the easy part of a modelling project: 252,000 rows, thirteen columns, no gaps. The cleaner the file looks, the more carefully it needs to be read. Perfect completeness in application data is unusual, and an income column without a stated period or currency is not a modelling detail — it determines whether the score means anything.
The decision
The lender needed to know which applications should go to manual review rather than straight-through processing, what evidence would justify that referral, and whether this file could support a credit decision at all. The output had to be a calibrated score with reason codes and a threshold linked to review capacity and expected loss — not a leaderboard of model accuracy.
What we worked with
252,000 applications with 13 fields:
- Applicant: age, income, profession, marital status, house ownership and car ownership.
- Employment: total experience and years in the current job.
- Location: city and state.
- Stability: years in the current house.
- Outcome: a risk flag on 12.3% of applications.
The traps we designed around
- Zero missing values is a finding, not a clean bill of health. Across a quarter of a million application records, every field is populated. Real intake data has gaps. Either the file was imputed upstream or it was generated as a curated extract. Either way, the imputation is undocumented, and claiming the data is clean would hide the assumption.
- Income has no unit. Values run from about 10,310 to 9,999,938 with a mean near 5.0 million, and the file states neither currency nor period. Read as monthly it is implausible; read as annual in a low-denomination currency it might not be. Reporting income as a currency figure would be an invention. It can be used as a relative measure, normalised and documented, or not used.
- Work history is internally impossible for some records. 19,121 rows report more total experience than the applicant's age allows after age 14, and 4,986 rows report more years in the current job than the same bound permits. Under 8% and under 2% respectively — small enough to be ignored, large enough to change a model if left untreated. They need an explicit rule: cap, flag or exclude.
- There is no time dimension. One row per application, no dates, no repayment history. Only a random split is possible, and if applicants can reappear in reality, a random split will overstate performance. That limitation belongs in the report, not in a footnote.
- The risk flag has no definition in the file. 12.3% is the rate in this extract, not necessarily the portfolio rate, and the label's measurement window is unknown. A model trained on an unexplained label inherits the ambiguity.
- The identifier is a row key. The ID column distinguishes rows, not customers. It cannot support repeat-applicant analysis.
- High-cardinality categories. 51 professions, 317 cities and 29 states, with inconsistent naming conventions mixing underscores and casing. Rare categories need grouping before they can be modelled.
- The file cannot make a credit decision. There is no loan amount, term, rate, bureau score or prior delinquency. It can support an application-time screen; it cannot price or approve a loan. Saying so early prevents a model that looks like a credit score but is not one.
How the analysis was built
- Define the grain and key. One row per application, with the ID confirmed as a row key rather than a customer key.
- Validate business rules before modelling. Age, experience and job tenure were checked against each other, and invalid records were flagged through a documented rule.
- Normalise income explicitly. The column was transformed into a relative, documented measure rather than being presented as a currency amount.
- Group rare categories. Professions and locations below a minimum frequency were pooled, with the grouping recorded so it can be reversed.
- Split and validate. A stratified split was used, with calibration and precision at the proposed operating threshold reported alongside discrimination.
- Tie the threshold to operations. The cut-off was set from review capacity and expected loss, not from a statistical convention.
- Attach reason codes and a gap list. The strongest stable drivers were translated into review reasons, and the missing credit fields were written up as a prioritised data request.
What this changes
- The conversation moves from score quality to operating cost. How many applications are reviewed, at what risk level, and what that costs is the decision the business can make.
- Impossible records get a rule. They are no longer silently averaged into the model.
- Income is no longer misreported. It is a documented index, not a currency claim.
- The scope is honest. The file supports screening, and the gap list states what is needed before it could support credit approval.
What you receive
- A cleaned application table with the grain, key and exclusion rules documented.
- A data-quality report covering impossible values, completeness and category cardinality.
- A calibrated risk score with reason codes and stability checks.
- A threshold memo tied to review capacity and expected loss.
- A prioritised request for the fields a credit decision would require.
Where this applies
The method fits consumer lenders, fintech underwriting teams and any application process that needs triage before manual review. The minimum inputs are an application identifier, an outcome label, applicant and employment attributes, and location. The first deliverable is usually the validation note — because a file with no missing values and an unlabelled income column needs its assumptions exposed before anyone builds on it.
This is an illustrative case study using an anonymized public lending dataset; it does not report results from a specific client engagement or a validated production credit model. It reflects our standard method for application risk screening.
