End-to-end machine learning project that predicts whether a loan applicant will default, built the way a production credit model should be: leakage-safe pipelines, honest cross-validated comparison of 7 classifiers, explicit class-imbalance handling, hyperparameter tuning, a single final test evaluation, and SHAP explainability.
Credit losses are one of the largest costs for any lender. Given borrower and loan characteristics (income, employment, credit history, loan amount, interest rate, …), the model estimates the probability of default so the business can decline or re-price the riskiest applications — and explain every decision.
| Source | Credit Risk Dataset (Kaggle) |
| Size | ~32,500 historical loans, 12 columns |
| Target | loan_status — 1 = default (~22%), 0 = repaid |
| Quirks handled | impossible ages (up to 144), 9.5% missing interest rates, duplicates |
The dataset is downloaded automatically with kagglehub on first run (no Kaggle account needed) — see src/data.py.
credit-risk-prediction/
├── data/ # raw dataset (auto-downloaded from Kaggle)
├── notebooks/
│ ├── 01_eda.ipynb # inspection, data quality, missing values, EDA
│ └── 02_modeling.ipynb # pipelines, 7 models, SMOTE, PCA, tuning, SHAP
├── src/
│ ├── config.py # paths & constants
│ ├── data.py # download / load / clean
│ ├── features.py # feature engineering + feature groups
│ ├── preprocessing.py # ColumnTransformer pipeline
│ ├── evaluate.py # metrics & plots
│ ├── train.py # retrain final model: python -m src.train
│ └── predict.py # score applications: python -m src.predict
├── models/ # final_model.joblib (full pipeline)
├── outputs/ # metrics tables, tuned params, figures/
├── requirements.txt
└── README.md
- EDA — class balance, missing-value analysis, outlier audit, default-rate breakdowns, correlations.
- Cleaning — rule-based only (impossible values, duplicates); everything statistical happens inside pipelines.
- Feature engineering — missing-value flags,
credit_hist_start_age, log-income;loan_gradeordinal-encoded (risk is monotone A→G). - Leakage-safe preprocessing —
ColumnTransformer(median impute + scale / mode impute + one-hot / ordinal) fitted inside every CV fold. - Model comparison — Logistic Regression, Decision Tree, Random Forest, KNN, SVM, XGBoost, LightGBM under one CV protocol.
- Imbalance handling —
class_weightand SMOTE (applied to training folds only viaimblearn.pipeline). - PCA experiment — tested and rejected with evidence (no gain, costs interpretability).
- Tuning —
RandomizedSearchCV(ROC-AUC) for XGBoost, LightGBM, Random Forest. - Final evaluation — the test set is opened exactly once; threshold analysis included.
- Explainability — native importances + SHAP beeswarm/bar with business interpretation.
| Model | Accuracy | Precision | Recall | F1 | ROC-AUC |
|---|---|---|---|---|---|
| XGBoost | 0.935 | 0.950 | 0.740 | 0.832 | 0.946 |
| LightGBM | 0.935 | 0.956 | 0.739 | 0.834 | 0.946 |
| Random Forest | 0.932 | 0.971 | 0.711 | 0.821 | 0.930 |
| KNN | 0.886 | 0.881 | 0.555 | 0.681 | 0.886 |
| SVM (RBF) * | 0.894 | 0.882 | 0.597 | 0.712 | 0.882 |
| Logistic Regression | 0.857 | 0.746 | 0.523 | 0.615 | 0.869 |
| Decision Tree | 0.885 | 0.723 | 0.766 | 0.744 | 0.842 |
* benchmarked on a stratified 8,000-row subsample (kernel SVMs scale ~O(n²)).
| Metric | Tuned LightGBM | Logistic Regression baseline |
|---|---|---|
| Accuracy | 0.940 | 0.851 |
| Precision | 0.978 | 0.722 |
| Recall | 0.743 | 0.519 |
| F1 | 0.845 | 0.604 |
| ROC-AUC | 0.954 | 0.868 |
At the default threshold the model catches ~74% of defaulters with under 3% false alarms among flagged loans. Class-imbalance handling (class_weight, fold-safe SMOTE) lifts defaulter recall to ~0.78–0.79 at a precision cost, and the notebook's threshold analysis turns that trade-off into an explicit business decision.
Detailed tables: outputs/cv_model_comparison.csv, outputs/imbalance_comparison.csv, outputs/test_set_results.csv.
git clone <this-repo>
cd credit-risk-prediction
python -m venv .venv
.venv\Scripts\activate # Windows (use: source .venv/bin/activate on macOS/Linux)
pip install -r requirements.txt
# Option A - notebooks (recommended): run 01_eda.ipynb then 02_modeling.ipynb
jupyter notebook notebooks/
# Option B - scripts
python -m src.train # downloads data, trains, evaluates, saves model
python -m src.predict # demo: scores 5 applications with the saved model- Fewer credit losses — ranking applications by predicted risk lets the lender decline or re-price the riskiest tail instead of using blunt rules.
- Defensible decisions — SHAP yields per-applicant reason codes ("high loan-to-income ratio"), supporting regulatory explainability requirements.
- A tunable dial — the threshold table converts model scores into an explicit cost/volume trade-off the credit team can own.
- Pipelines +
ColumnTransformerare the backbone of leak-free ML — every fitted statistic stays inside its CV fold. - SMOTE belongs inside the pipeline; applied before splitting, it silently inflates scores.
- Rebalancing mainly moves the precision/recall trade-off; ranking quality (AUC) comes from features and model class.
- PCA is not a free win — on a compact, interpretable feature space it costs more than it gives.
Dataset by Lao Tse on Kaggle. Built with scikit-learn, XGBoost, LightGBM, imbalanced-learn and SHAP.



