Skip to content

xyzprtk/meridan

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

15 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Meridian — Credit Risk Scorecard

A full-stack machine learning demo that predicts credit risk scores and default probabilities from real financial data. Built with FastAPI (Python backend) and Next.js 14+ (React frontend), it showcases a complete production-ready pipeline from data cleaning to an animated, explainable UI.

Disclaimer: This is a data science demo built on the Kaggle Give Me Some Credit dataset. It is not for actual lending decisions.


What It Does

Meridian takes an applicant's financial and credit history data — age, income, debt ratios, past delinquencies, open credit lines — and produces:

  • A credit risk score from 100 to 670
  • A default probability (chance of going 90+ days past due within 2 years)
  • A risk category (Very Low → Very High Risk)
  • A per-factor breakdown showing exactly which variables helped or hurt the score

Every prediction is fully explainable. You can see the bin each value fell into, the points it contributed, and how much it mattered relative to other factors.


Architecture

credit-risk-scorecard/
├── backend/                          # FastAPI Python server
│   ├── train_model.py               # Trains model & exports artifacts
│   ├── main.py                      # FastAPI app with /predict endpoint
│   ├── requirements.txt             # Python dependencies
│   └── artifacts/
│       └── scorecard_artifacts.pkl  # Trained model, bins, scorecard table
├── frontend/                         # Next.js 14+ App Router
│   ├── app/
│   │   ├── page.tsx                 # Landing page
│   │   ├── predict/page.tsx         # Wizard + results
│   │   ├── api/predict/route.ts     # Proxy to FastAPI
│   │   ├── layout.tsx               # Root layout with pill navbar
│   │   └── globals.css              # Charcoal + Mint/Coral theme
│   ├── components/
│   │   ├── wizard-form.tsx          # 3-step input wizard
│   │   ├── result-card.tsx          # Score display + breakdown
│   │   ├── theme-toggle.tsx         # Sun/moon icon switcher
│   │   ├── theme-provider.tsx       # Dark mode context
│   │   └── app-logo.tsx             # Gauge dial SVG logo
│   └── public/
│       └── logo.svg                 # Standalone logo asset
├── Data/
│   └── cs-training.csv              # 150K training records
└── credit-risk-scorecard.ipynb      # Original Jupyter notebook

Tech Stack

Backend

Technology Purpose
FastAPI High-performance async API framework
Pydantic Request/response validation
scikit-learn Logistic Regression model
optbinning Optimal binning with monotonic constraints
pandas / numpy Data preprocessing
pickle Model artifact serialization

Frontend

Technology Purpose
Next.js 14+ App Router, React Server Components
TypeScript Type safety across the stack
Tailwind CSS Utility-first styling
shadcn/ui Accessible, composable UI primitives
Framer Motion Entrance animations, page transitions, micro-interactions
Geist Sans-serif font (Vercel)

Features

Landing Page (/)

  • Animated hero with a gauge dial SVG that draws itself in
  • Mini chart preview of what the results look like
  • 4-step pipeline explanation (Clean → Bin → WoE → Score)
  • Interactive preview card with score, probability, and factor breakdown
  • Staggered scroll-reveal animations on every section

Predictor (/predict)

  • 3-step wizard with slide transitions between steps:
    1. Personal Information (Age, Income, Dependents)
    2. Credit Profile (Utilization, Debt Ratio, Open Lines, Real Estate)
    3. Payment History (30-59, 60-89, 90+ day delinquencies)
  • Real-time field validation with animated error messages
  • Animated progress indicators per step

Results

  • Score counter that animates from 0 to the final score
  • Circular gauge arc that draws itself in
  • Risk badge with color-coded category
  • Probability bar that grows to the score position
  • Factor breakdown with staggered reveals:
    • Green section: factors helping the score
    • Red section: factors hurting the score
    • Each bar grows from 0 to its contribution percentage
  • Detailed metrics grid with staggered entrance

Theme

  • Light / Dark mode toggle in the navbar
  • Persists preference in localStorage
  • Respects system preference on first visit
  • Charcoal + Mint/Coral color palette adapts to both modes

Navbar

  • Floating pill-shaped navbar with backdrop blur
  • Gauge dial SVG logo next to "Meridian" text
  • Mint "Try the predictor" button
  • Animated sun/moon theme toggle

How It Works (The ML Pipeline)

The model was trained on the Give Me Some Credit dataset (150,000 records).

1. Data Cleaning

  • Median imputation for missing MonthlyIncome and NumberOfDependents
  • Missing flags created to preserve the signal of missingness
  • 609 exact duplicates removed
  • Outliers in RevolvingUtilizationOfUnsecuredLines and DebtRatio capped at 99th percentile

2. Optimal Binning

Each of the 10 numeric variables is split into risk segments using OptimalBinning with monotonic constraints. This ensures each bin makes statistical sense and maintains a monotonic relationship with default risk.

3. Weight of Evidence (WoE)

Each bin is converted to a WoE value:

WoE = ln( (% of non-defaulters in bin) / (% of defaulters in bin) )

This linearizes the log-odds relationship and makes the model transparent.

4. Logistic Regression

A logistic regression model is trained on the WoE-transformed features. Coefficients are stable, interpretable, and regulator-friendly.

5. Score Scaling

The model's log-odds output is converted to a 100–670 score:

Score = Offset - Factor × ln(Odds)

Where:

  • Base Score = 385
  • PDO = 40 (Points to Double the Odds)
  • Base Odds = 1:19

Higher score = Lower risk.


API

POST /predict

Accepts applicant data and returns the prediction.

Request:

{
  "RevolvingUtilizationOfUnsecuredLines": 0.5,
  "age": 35,
  "NumberOfTime30_59DaysPastDueNotWorse": 0,
  "DebtRatio": 0.3,
  "MonthlyIncome": 5000,
  "NumberOfOpenCreditLinesAndLoans": 5,
  "NumberOfTimes90DaysLate": 0,
  "NumberRealEstateLoansOrLines": 1,
  "NumberOfTime60_89DaysPastDueNotWorse": 0,
  "NumberOfDependents": 2
}

Response:

{
  "score": 670,
  "probability": 0.0484,
  "risk_category": "Very Low Risk",
  "risk_color": "emerald",
  "breakdown": [
    {
      "variable": "RevolvingUtilizationOfUnsecuredLines",
      "value": 0.5,
      "bin": "[0.49, 0.70)",
      "points": -13.22,
      "contribution_pct": 82.0
    }
  ],
  "base_score": 385.0,
  "total_points": 21.45
}

GET /health

Returns service status.

{
  "status": "ok",
  "model_loaded": true
}

Running Locally

Prerequisites

  • Python 3.10+
  • Node.js 18+

1. Clone & Setup

git clone <repo-url>
cd credit-risk-scorecard

2. Backend

cd backend

# Install dependencies
pip install -r requirements.txt

# Train and export model artifacts (one-time)
python train_model.py

# Start the server
python -m uvicorn main:app --reload --port 8000

The API will be available at http://127.0.0.1:8000.

3. Frontend

cd frontend

# Install dependencies
npm install

# Start dev server
npm run dev

The frontend will be available at http://localhost:3000 (or the next available port).

4. Open in Browser

Navigate to http://localhost:3000 and click "Try the predictor".


Building for Production

Backend

cd backend
python -m uvicorn main:app --host 0.0.0.0 --port 8000

Frontend

cd frontend
npm run build
npm start

Project Structure Details

Backend Files

File Purpose
train_model.py Loads cs-training.csv, cleans data, fits OptimalBinning models, trains logistic regression, exports scorecard_artifacts.pkl
main.py FastAPI app. Loads artifacts, defines Pydantic schemas, implements /predict and /health endpoints
requirements.txt Python dependencies
artifacts/scorecard_artifacts.pkl Pickled dictionary containing: binning models, LR model, selected variables, scorecard table, preprocessing params, scoring params

Frontend Files

File Purpose
app/page.tsx Landing page with hero, pipeline strip, feature list, preview card, CTA, footer
app/predict/page.tsx Predictor page with wizard form and result card switching
app/layout.tsx Root layout with Geist font, pill navbar, theme provider
app/globals.css Charcoal + Mint/Coral CSS variables, light/dark themes
components/wizard-form.tsx Multi-step form with Framer Motion slide transitions
components/result-card.tsx Animated score display with count-up, gauge draw-in, staggered breakdown
components/theme-provider.tsx React context for light/dark mode with localStorage persistence
components/theme-toggle.tsx Animated sun/moon icon button
components/app-logo.tsx Inline gauge dial SVG logo
public/logo.svg Standalone logo asset

Design Choices

Why WoE + Logistic Regression?

This is the industry standard for credit scorecards because it is:

  • Transparent — regulators can inspect bin contributions
  • Stable — monotonic bins prevent overfitting
  • Interpretable — each feature's contribution is a simple linear term

Why FastAPI + Next.js?

  • FastAPI provides automatic API documentation (/docs), type validation, and high performance
  • Next.js App Router enables server-side rendering for the landing page while keeping the wizard fully client-side

Why a Proxy Route?

The frontend calls /api/predict (an internal Next.js Route Handler) which proxies to FastAPI. This keeps the backend URL server-side and avoids CORS issues.


Known Issues

OptBinning + scikit-learn 1.6+

If you see TypeError: check_array() got an unexpected keyword argument 'force_all_finite', downgrade scikit-learn:

pip install "scikit-learn<1.6"

Uvicorn Python Mismatch

If uvicorn fails with ModuleNotFoundError: No module named 'fastapi', use python -m uvicorn instead of the bare uvicorn command to ensure the correct Python interpreter is used.


Future Enhancements

  1. Batch Scoring — Upload a CSV and receive a scored file
  2. Authentication — Add login/session management for production use
  3. Database — Store predictions in PostgreSQL for audit trails
  4. Monitoring — Track PSI (Population Stability Index) and model drift
  5. Dark Mode Refinement — Further polish dark theme colors
  6. Animations — Add Framer Motion page transitions between routes

Dataset

Built using the Give Me Some Credit dataset from Kaggle.


License

This project is for educational and demonstration purposes only.

About

An end-to-end credit risk scorecard platform built with Next.js and FastAPI, featuring WoE binning, Logistic Regression, explainable scoring, and borrower risk analysis.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors