A machine learning project that predicts the presence of chronic kidney disease from routine clinical test results, using six ensemble classifiers and a Flask web app for real-time predictions.
Built for CSE6505 – Machine Learning (CCP Project), Lahore Garrison University.
This project trains and compares six ensemble machine learning models on the UCI Chronic Kidney Disease dataset, then serves the best-performing model through a simple web interface where a clinician can enter a patient's lab values and get an instant CKD risk prediction.
- Best model: Voting Classifier — 100% accuracy, 100% AUC-ROC on the held-out test set
- Dataset: 397 patients, 24 clinical attributes (11 numeric, 13 categorical)
- Pipeline: ARFF → CSV conversion, MICE/mode imputation, encoding, scaling, SVM-SMOTE balancing, 6-model ensemble training, full evaluation suite
- Deployment: Flask app with an interactive form-based UI
ckd_project/
├── app.py # Flask web application (prediction API + UI)
├── ckd_analysis.ipynb # End-to-end notebook: EDA → preprocessing → training → evaluation
├── model_metrics.csv # Summary table of all 6 models' performance
│
├── Chronic_Kidney_Disease/
│ ├── chronic_kidney_disease.arff # Original UCI dataset
│ ├── chronic_kidney_disease_full.arff # Full/cleaned ARFF source used by the notebook
│ └── chronic_kidney_disease.info.txt # Official UCI attribute documentation
│
├── data/
│ └── ckd_raw.csv # Dataset converted from ARFF to CSV (397 rows × 25 cols)
│
├── models/ # Trained models + preprocessing artifacts (joblib .pkl)
│ ├── preprocessors.pkl # Scaler, imputers, label encoders, feature names
│ ├── Random_Forest.pkl
│ ├── Gradient_Boosting.pkl
│ ├── AdaBoost.pkl
│ ├── Voting_Classifier.pkl # ← model used in production (app.py)
│ ├── Stacking_Classifier.pkl
│ └── Bagging_Classifier.pkl
│
├── outputs/ # Generated plots and metrics from the notebook run
│ ├── 01_missing_class.png # Missing-value heatmap + class distribution
│ ├── 02_numeric_distributions.png# Numeric feature distributions by class
│ ├── 03_correlation.png # Correlation heatmap (numeric features)
│ ├── 04_categorical.png # Categorical feature breakdowns
│ ├── 05_confusion_matrices.png # Confusion matrix per model
│ ├── 06_model_comparison.png # Bar chart comparing all metrics across models
│ ├── 07_roc_curves.png # ROC curves for all models
│ ├── 08_feature_importance.png # Feature importances from the best model
│ ├── 09_cross_validation.png # 10-fold CV accuracy comparison
│ └── model_metrics.csv # Same metrics table, written by the notebook
│
└── templates/
└── index.html # Frontend form for the Flask app
Source: UCI Machine Learning Repository – Chronic Kidney Disease Data Set, collected by Dr. P. Soundarapandian (Apollo Hospitals, Tamil Nadu, India) and donated by L. Jerlin Rubini, Alagappa University (2015).
- Instances: 400 patients originally (397 retained after cleaning) — 250 CKD / 150 not-CKD (approx., before cleaning)
- Attributes: 24 clinical features + class label
| Code | Feature | Code | Feature |
|---|---|---|---|
age |
Age | pcv |
Packed cell volume |
bp |
Blood pressure | wc |
White blood cell count |
sg |
Specific gravity | rc |
Red blood cell count |
al |
Albumin | htn |
Hypertension |
su |
Sugar | dm |
Diabetes mellitus |
rbc |
Red blood cells | cad |
Coronary artery disease |
pc |
Pus cell | appet |
Appetite |
pcc |
Pus cell clumps | pe |
Pedal edema |
ba |
Bacteria | ane |
Anemia |
bgr |
Blood glucose random | sc |
Serum creatinine |
bu |
Blood urea | sod |
Sodium |
hemo |
Hemoglobin | pot |
Potassium |
Full attribute descriptions are in Chronic_Kidney_Disease/chronic_kidney_disease.info.txt.
The complete pipeline is implemented in ckd_analysis.ipynb:
- Data loading — parses the raw
.arfffile and converts it todata/ckd_raw.csv. - Exploratory Data Analysis — missing value patterns, class balance, numeric/categorical distributions, correlation analysis (saved to
outputs/01–04). - Preprocessing
- Target encoding (
ckd= 1,notckd= 0) - Categorical features label-encoded
- Numeric features imputed via Iterative Imputer (MICE); categorical features imputed via most-frequent value
- StandardScaler applied to all features
- Train/test split (80/20, stratified) performed before resampling to avoid leakage
- SVM-SMOTE applied to the training set only, to correct class imbalance
- Target encoding (
- Model training — six ensemble classifiers trained on the resampled training set, evaluated on the untouched test set, with 10-fold stratified cross-validation for robustness:
- Random Forest (200 trees,
max_features='sqrt') - Gradient Boosting (200 estimators, depth 4, lr 0.05)
- AdaBoost (depth-2 stumps, 100 estimators)
- Voting Classifier (soft voting: RF + GB + Logistic Regression)
- Stacking Classifier (RF + GB + KNN → Logistic Regression meta-learner)
- Bagging Classifier (100 decision trees)
- Random Forest (200 trees,
- Evaluation — accuracy, precision, recall, F1, AUC-ROC, and cross-validated accuracy for every model, plus confusion matrices, ROC curves, and feature importance plots (
outputs/05–09). - Artifact export — all trained models and the fitted preprocessing objects are saved to
models/viajoblib.
| Model | Accuracy | Precision | Recall | F1-Score | AUC-ROC | CV Mean ± Std |
|---|---|---|---|---|---|---|
| Random Forest | 98.75% | 100.00% | 98.00% | 98.99% | 100.00% | 99.00% ± 1.22% |
| Gradient Boosting | 95.00% | 96.00% | 96.00% | 96.00% | 99.73% | 97.00% ± 2.45% |
| AdaBoost | 100.00% | 100.00% | 100.00% | 100.00% | 100.00% | 99.50% ± 1.00% |
| Voting Classifier | 100.00% | 100.00% | 100.00% | 100.00% | 100.00% | 99.75% ± 0.75% |
| Stacking Classifier | 97.50% | 96.15% | 100.00% | 98.04% | 100.00% | 99.50% ± 1.00% |
| Bagging Classifier | 96.25% | 96.08% | 98.00% | 97.03% | 99.67% | 96.75% ± 2.51% |
The Voting Classifier was selected as the production model (highest accuracy with the lowest cross-validation variance) and is the model loaded by app.py.
Note: near-perfect scores on a small (397-row), single-source dataset are expected and should be interpreted cautiously — see Limitations below.
app.py is a lightweight Flask app that:
- Serves a clinical data-entry form (
templates/index.html) - Accepts patient lab values via a
/predictPOST endpoint - Applies the saved preprocessors (imputers + scaler) and the Voting Classifier model
- Returns a prediction (
CKD Detected/No CKD Detected), CKD probability, and a risk level (Low / Medium / High)
pip install flask numpy joblib scikit-learn
python app.pyThen open http://localhost:5000 in your browser.
Note:
app.pycurrently loads the model from a hardcoded Windows path:MODEL_DIR = r'C:\Users\SK COMPUTERS\Documents\ckd_project\models'Update this to a relative path (e.g.
MODEL_DIR = os.path.join(os.path.dirname(__file__), 'models')) before running on another machine.
flask
numpy
pandas
scikit-learn
imbalanced-learn
matplotlib
seaborn
joblib
scipy
- The dataset is small (397 patients) and from a single hospital source, which inflates apparent model performance and limits generalizability to other populations.
- This tool is built for an academic course project and is not a certified medical device. It should not be used for actual clinical diagnosis or treatment decisions without validation by qualified medical professionals.
- Dataset: Dr. P. Soundarapandian (Apollo Hospitals), L. Jerlin Rubini & Dr. P. Eswaran (Alagappa University) — via the UCI Machine Learning Repository.