Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 

Repository files navigation

LimitForge

A dynamic credit limit recommendation engine that combines spend forecasting, default-risk modeling, and a learned recommendation layer to suggest a risk-adjusted credit limit for each customer — the same kind of problem a credit-card issuer's portfolio risk team works on.

Given a customer's spending history, payment behavior, utilization, and demographics, recommend an optimal credit limit that balances growth opportunity against default risk.

Why this project

Most "default prediction" or "churn prediction" portfolios look the same. This one is different because it's a full decision pipeline, not a single classifier: it forecasts future behavior, prices risk, and turns both into a single actionable number a card issuer could actually act on — which is closer to how risk and growth teams at issuers like Amex or Chase actually operate.

Architecture

                ┌────────────────────────┐
   customer  →  │  Feature Engineering    │
   history      │  (utilization, payment  │
                │   ratios, late-pay,      │
                │   spend trend)           │
                └───────────┬─────────────┘
                            │
              ┌─────────────┼─────────────┐
              ▼                           ▼
  ┌───────────────────────┐   ┌───────────────────────────┐
  │ Spend Forecast Model    │   │ Default Risk Model         │
  │ Linear Regression       │   │ Logistic Regression        │
  │ → predicted next-month  │   │ → probability of default   │
  │   spend                 │   │   next month                │
  └───────────┬───────────┘   └─────────────┬──────────────┘
              │                              │
              └──────────────┬───────────────┘
                              ▼
                ┌──────────────────────────────┐
                │ Limit Recommendation Engine   │
                │ XGBoost (learns a risk-       │
                │ adjusted limit policy)         │
                │ → recommended credit limit     │
                └──────────────────────────────┘

The three models

# Model Type Predicts
1 Spend Forecast Model Linear Regression Next month's spend, from 5 months of billing history
2 Default Risk Model Logistic Regression Probability of default next month
3 Limit Recommendation Engine XGBoost (gradient boosted trees) Final recommended credit limit

A note on the recommendation engine's training target

No public dataset includes a ground-truth "ideal credit limit" — that's an internal business decision issuers make, not something that gets published. So model 3 is trained in two honest steps:

  1. A simple, explicit business rule (compute_business_rule_limit in src/limit_recommendation_engine.py) gives each customer enough headroom to cover ~1.2×–3× their predicted spend, where the multiplier shrinks as default probability rises, capped so no limit can more than double or less than halve in one cycle (real issuers don't swing limits 5x overnight).
  2. XGBoost is trained to learn and generalize that policy from the engineered features, rather than just looking it up. In a real deployment, this is the part you'd continuously retrain on actual realized outcomes (did the customer default after their limit changed? did they grow their spend?) so the model adapts past the hand-written starting rule.
  3. A hard guardrail clip at inference time (recommend_credit_limit) re-applies the same growth/shrink bounds to the model's output. A learned model is an approximation, not a guarantee — it can drift slightly past the policy bounds on individual predictions, so the final serving step never lets a recommendation violate the stated policy, even by a little.

This is a standard pattern when you don't have outcome-labeled "optimal action" data, and it's worth explaining exactly this way in an interview — it shows you understand the difference between a label you have and a label you're approximating.

Dataset

Default of Credit Card Clients Dataset — 30,000 real customers with 6 months of billing/payment history and a real, labeled default outcome. See data/README.md for download instructions. If you run the pipeline without the real CSV, it automatically falls back to a synthetic dataset with an identical schema so you can smoke test it.

Results (real dataset — 30,000 customers)

Spend Forecast Model (Linear Regression)

MAE RMSE
8,856.92 22,665.54 0.91

Default Risk Model (Logistic Regression)

Accuracy Precision Recall F1 ROC-AUC
0.738 0.433 0.607 0.506 0.748

A ROC-AUC of ~0.75 from plain logistic regression is in line with published benchmarks for this dataset — gradient-boosted models (the recommendation engine below) typically push that closer to ~0.78. Recall is prioritized over precision here (class_weight="balanced") since for a credit issuer, missing an actual default is more costly than over-flagging a safe customer.

Limit Recommendation Engine (Gradient Boosted Trees)

MAE RMSE
4,880.28 9,921.65 1.00

The R² here is near 1.0 because this model is trained to approximate the explicit business rule (see below) from features that mostly determine that rule directly — it's measuring how well the model learned the policy, not an independent predictive task. That's expected and worth explaining as such.

ROC curve, confusion matrix, and feature importance plots are saved to outputs/plots/ after running the pipeline.

Project structure

LimitForge/
├── data/
│   └── README.md                       # how to get the real dataset
├── src/
│   ├── data_loader.py                  # loads real data, falls back to synthetic
│   ├── synthetic_data.py               # synthetic demo dataset (same schema)
│   ├── feature_engineering.py          # utilization, payment ratios, trends
│   ├── spend_forecast_model.py         # Model 1: Linear Regression
│   ├── default_risk_model.py           # Model 2: Logistic Regression
│   ├── limit_recommendation_engine.py  # Model 3: XGBoost + business-rule target
│   └── utils.py                        # plotting + save/load helpers
├── outputs/
│   ├── models/                         # saved .pkl artifacts (gitignored)
│   └── plots/                          # ROC curve, confusion matrix, feature importance
├── main.py                             # runs the full pipeline end to end
├── requirements.txt
└── README.md

Quickstart

git clone https://github.com/<your-username>/LimitForge.git
cd LimitForge
pip install -r requirements.txt

# Optional but recommended: download the real dataset (see data/README.md)
# and place it at data/UCI_Credit_Card.csv

python main.py

This trains all three models, saves them to outputs/models/, saves evaluation plots to outputs/plots/, and prints sample recommendations for the first 5 customers, e.g.:

{
  "current_limit": 50000.0,
  "predicted_next_month_spend": 49174.86,
  "default_probability": 0.3715,
  "recommended_limit": 100000.0,
  "change": 50000.0,
  "pct_change": 100.0
}

Using it on a single customer

from src.data_loader import load_data
from src.feature_engineering import add_engineered_features
from src.spend_forecast_model import train_spend_model, predict_future_spend
from src.default_risk_model import train_default_model, predict_default_probability
from src.limit_recommendation_engine import (
    build_recommendation_dataset, train_recommendation_engine, recommend_credit_limit
)

df = add_engineered_features(load_data())

spend_artifacts, _ = train_spend_model(df)
predicted_spend = predict_future_spend(spend_artifacts, df)

risk_artifacts, _, _ = train_default_model(df)
default_prob = predict_default_probability(risk_artifacts, df)

X, y = build_recommendation_dataset(df, predicted_spend, default_prob)
rec_artifacts, _ = train_recommendation_engine(X, y)

customer = df.iloc[0]
print(recommend_credit_limit(rec_artifacts, customer, predicted_spend[0], default_prob[0]))

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages