Analysts need a repeatable way to score new applicants against patterns learned from historical loan outcomes. I trained a logistic-regression risk model on historical loan outcomes, then built a derived dataset that scores every applicant and feeds a working underwriting console — risk score, repayment odds, and tiered recommendation, per applicant, not just a model demo.
The risk model is a functioning backend trained on ~396,000 historical loans. The Lovable UX above remains a clickable design mock; the underwriting console is a separate Flask app that runs on real model output — a derived dataset scores every applicant offline, and the console reads that, not a live model call.
WhoCredit analysts reviewing loan applicationsDecide whether to approve, flag for review, or reject each new applicant.
WhatScore new applicants against real repayment historyTurn an applicant's profile into a default probability, then into decisions analysts can act on.
Why~77% accuracy, ~80% AUCValidated on held-out loans the model never trained on, not just fit to the training set.
The core question
Given an applicant's profile — amount, term, rate, grade, income, DTI, credit history, purpose, and more — how likely are they to default? That default probability is translated into operational outputs analysts can act on: a 0–100 risk score, repayment odds, and tiered recommendations such as APPROVE, APPROVE_WITH_CONDITIONS, REVIEW_MANUAL, or REJECT.
Bottom line
An offline-trained logistic regression credit-default model for LoanTap-style applications. Training used ~396k historical loans; live use only scores new applications and does not update the model from API or UI users.
Two things that were broken
Manual review, one file at a time
High application volume met a review process that was slow and inconsistent from analyst to analyst.
No check against real outcomes
Approve or reject calls weren't tested against what actually happened to past borrowers who looked similar.
What we changed
Trained on what actually happenedLogistic regression fit on ~396,000 historical loans, learning real repayment and default patterns, not assumptions.
Turned one score into decisionsThe same default probability reformatted into a risk score, repayment odds, and a four-tier recommendation.
Made the reasoning visibleLogistic regression coefficients and rule-based risk tags (e.g. high DTI, low income), not a black-box number.
Closed the loop from model to staff toolBuilt a derived dataset that scores every applicant against the trained model, then feeds a working underwriting console — not a UI mock running on placeholder numbers.
Validated the tiers against real outcomesBecause the scored applicants are closed historical loans, I could check whether the recommendation tiers actually track repayment — and they do.
The working underwriting console: pick a case from the queue, see the risk score, the drivers behind it, and a policy recommendation — not a UI mock on placeholder numbers.
Same case: an AI summary the underwriter can accept or override, with Approve / Escalate / Decline on the same screen.
A scored queue with the reasoning on every row — risk score, tier, and policy action, filterable by the analyst.
One default probability, reshaped into a risk score, repayment odds, and a recommendation.
income, DTI, credit history, loan grade, purpose, and more
4-tier recommendation
Not just approve or reject
APPROVE → APPROVE WITH CONDITIONS → REVIEW MANUAL → REJECT
The same accuracy and AUC, shown in the analyst panel — with the calibration caveat that keeps the risk tiers percentile-based rather than fixed probability cutoffs.
Does the tiering actually work?
The derived dataset scores the full historical portfolio, and because those loans are already closed, the actual outcome is known. Charge-off rate rises monotonically across the four tiers — the check that was missing when the staff tool ran on disconnected mock data.
5.9% → 43%
Actual charge-off rate, APPROVE to REJECT
5,000-applicant derived dataset, sampled from the full ~396K portfolio
Derived from the model's own coefficients, shown per applicant in the console
Across the full 396k book, historical default rate climbs from 6.9% (Low) to 45.3% (Very High) — a clean, monotonic climb across tiers.
Concrete cases at both ends of the book — including one Very High-risk loan that still paid in full, a reminder that the score sets probabilities, not certainties.
Business impact
Faster decisionsStreamlined workflows cut review time, enabling higher application throughput.
Lower credit lossesBetter risk detection reduces defaults and charge-offs by identifying high-risk patterns in applicant profiles.
Stronger adoptionAn intuitive interface made the ML technology accessible to non-technical users from day one.
Analysis of the ~396k-record training set showed debt consolidation loans comprise a large share of applications, with interest rate and credit grade among the strongest default predictors. Borrowers with verified income, individual (non-joint) applications, and 36-month terms tended to show better repayment performance — patterns reflected in the engineered feature set.
Default rate sliced four ways: grade, purpose, home ownership, and term. 60-month loans default at roughly double the rate of 36-month loans.
What the model itself says is driving risk: grade, DTI, and 60-month terms push it up; income, credit history, and employment tenure push it down.
Every segment ranked — Grade G, F, E, 60-month terms, and small-business purpose sit above the 25% default-rate watch line.