Skip to content

Latest commit

 

History

10 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

🏥 Medical Risk & Disease Prediction System

Python FastAPI Scikit-learn Pandas NumPy JavaScript HTML5 License

A research and educational machine-learning system that analyzes patient-related features to estimate health risk levels and disease-risk scores — served through a FastAPI backend and an interactive web dashboard.

⚠️ This is an educational and research-oriented project. It is not a clinical diagnostic tool and must not be used as a substitute for professional medical advice.


📖 Table of Contents


🎯 Overview

This project is a supervised machine-learning prototype for health risk assessment. It accepts structured patient data — including vitals, medical history, symptoms, and lifestyle factors — and produces:

  • A risk classification (Low / Medium / High)
  • A risk percentage score (0–100%)
  • A natural-language explanation of the contributing factors
  • Personalized health recommendations

The system is composed of a Python/FastAPI backend that loads two trained scikit-learn models (a Random Forest Classifier and a Random Forest Regressor), and a plain HTML/CSS/JavaScript frontend dashboard that communicates with the API.

The project is intended for software portfolio demonstration, ML experimentation, and educational exploration of health-risk modeling. It has not been clinically validated.


✨ Key Features

🧠 Risk Classification

Predicts one of three categorical risk levels — Low, Medium, or High — using a trained Random Forest Classifier with probability-based inference.

📊 Risk Score Regression

Produces a continuous risk percentage (5–95%) using a trained Random Forest Regressor. The final score is a weighted combination of the classifier's probability output (70%) and the regressor's direct prediction (30%).

🧬 Feature Engineering

Raw patient inputs are transformed into 7 engineered numerical features before being passed to the models: age, bmi_score, bp_risk, sugar_risk, symptom_score, lifestyle_score, history_score

🩺 Medical Rule Overrides

A post-prediction rule layer applies medical heuristics to override ML outputs in clearly healthy or clearly high-risk profiles, improving clinical plausibility.

🔍 Explainable Output

The system generates a plain-language explanation of the top contributing risk factors and up to 5 personalized health recommendations per prediction.

⚡ FastAPI Backend

RESTful API with Pydantic input validation, CORS support, startup model loading, graceful fallback to dummy models, and a /health endpoint.

💻 Interactive Web Dashboard

A Tailwind CSS dashboard with a patient input form, animated risk gauge, progress bars for disease probability indicators, and real-time API integration.

🛡️ Input Validation

Both backend (Pydantic schema + manual range checks) and frontend (JavaScript form validation) validate inputs before any prediction is made.


🏗️ System Architecture

flowchart LR
    A[User] --> B[Web Frontend\nHTML / CSS / JS]
    B --> C[FastAPI Backend\nPOST /predict]
    C --> D[Pydantic Validation\n+ Range Checks]
    D --> E[Feature Engineering\n7 Engineered Features]
    E --> F[StandardScaler]
    F --> G[Random Forest\nClassifier]
    F --> H[Random Forest\nRegressor]
    G --> I[Medical Rule\nOverride Layer]
    H --> I
    I --> J[PredictionResponse\nrisk_level · risk_percentage\nexplanation · recommendations\nconfidence]
    J --> B
Loading

🔄 How It Works

1. Patient fills the web form
         ↓
2. JavaScript validates and serializes input
         ↓
3. POST /predict → FastAPI backend
         ↓
4. Pydantic schema validation + manual range checks (age, height, weight)
         ↓
5. Feature engineering → 7 numerical features
         ↓
6. StandardScaler normalization
         ↓
7. Random Forest Classifier → class probabilities → risk level + probability-mapped percentage
   Random Forest Regressor  → direct risk percentage
         ↓
8. Weighted combination: 70% classifier-derived % + 30% regressor %
         ↓
9. Medical rule override (healthy profile → cap at Low; 3+ high-risk factors → floor at High)
         ↓
10. Explanation + recommendations generated from input flags
         ↓
11. PredictionResponse returned as JSON
         ↓
12. Frontend animates risk gauge, updates risk level badge, renders recommendations

🧬 Medical Feature Engineering

All raw patient inputs are reduced to 7 engineered features. These are heuristic transformations designed to capture medical risk signals — they are not clinically validated scoring systems.

Feature Derivation
age Raw age in years
bmi_score BMI = weight(kg) / height(m)² → scored 0 (underweight) to 3 (obese ≥30)
bp_risk Systolic/diastolic thresholds → scored 0 (normal <120/80) to 3 (stage 2 ≥160/100)
sugar_risk 2 if diabetes is True, else 0
symptom_score Weighted sum: chest_pain=3, shortness_of_breath=3, fatigue=2, frequent_urination=2, headache=1, fever=1
lifestyle_score activity_map(Low=2,Medium=1,High=0) + (9 − sleep_hours) + stress_level
history_score Sum of boolean flags: family_history + hypertension + smoking + alcohol

Medical Rule Override Logic

After ML inference, a rule layer adjusts the output:

  • Healthy override: If BMI < 25, BP < 130/85, no diabetes/hypertension/smoking, no symptoms, age < 50, activity ≥ Medium, sleep ≥ 7h, stress ≤ 2 → forces Low risk, caps percentage at 25%
  • High-risk override: If 3 or more of the following are true (age > 65, BMI > 30, BP > 160/100, diabetes, hypertension, smoking, chest pain, shortness of breath, stress > 4) → forces High risk, floors percentage at 65%

📚 Dataset

The training dataset is synthetically generated using training/create_balanced_dataset.py. It does not represent real patient records and should not be interpreted as clinical data.

Property Value
Total samples 1,500
Class distribution 500 Low / 500 Medium / 500 High (perfectly balanced)
Train / Test split 80% / 20% (stratified)
Features 22 raw columns → 7 engineered features
Target (classification) risk_level (Low / Medium / High)
Target (regression) risk_percentage (integer, 10–95%)
Random seed 42

How the Dataset is Generated

Each class is generated with statistically distinct parameter ranges:

  • Low risk: age 18–45, normal BMI, BP 100–130/60–85, no diabetes, mostly non-smokers, minimal symptoms, high/medium activity, sleep 7–9h, stress 1–3
  • Medium risk: age 35–60, overweight BMI, BP 130–150/80–95, some diabetes/hypertension, some symptoms, moderate lifestyle, sleep 5–8h, stress 2–4
  • High risk: age 50–80, obese BMI, BP 140–180/90–110, high diabetes/hypertension rates, multiple symptoms, poor lifestyle, sleep 4–7h, stress 3–5

Risk percentages are assigned randomly within class-appropriate ranges (Low: 10–30%, Medium: 30–65%, High: 65–95%) and are not derived from a clinical formula.


🤖 Machine Learning Models

Risk Classifier — RandomForestClassifier

Parameter Value
Algorithm Random Forest Classifier
n_estimators 200
max_depth 12
class_weight balanced
max_features sqrt
Preprocessing StandardScaler
Output Probability vector → Low / Medium / High

Prediction uses predict_proba rather than predict directly. The class probability is mapped to a percentage range (Low: 10–30%, Medium: 30–60%, High: 60–95%) before being combined with the regressor output.

Risk Regressor — RandomForestRegressor

Parameter Value
Algorithm Random Forest Regressor
n_estimators 100
max_depth 15
Preprocessing Shared StandardScaler from classifier training
Output Continuous risk percentage (clipped to 5–95%)

Final Score Combination

final_risk_percentage = (classifier_probability_percentage × 0.7) + (regressor_prediction × 0.3)

Clipped to [5, 95] before medical rule overrides are applied.


📈 Model Evaluation

The evaluation script (training/evaluate.py) implements the following:

Classification: 5-fold Stratified Cross-Validation (accuracy), full-dataset classification report (precision, recall, F1), confusion matrix, and risk-level distribution comparison.

Regression: 5-fold Cross-Validation (MAE), full-dataset MAE and R² score, and MAE broken down by risk percentage range (0–25%, 25–50%, 50–75%, 75–100%).

Medical relevance test cases: Three hand-crafted scenarios (healthy young adult, medium-risk middle-aged, high-risk elderly) are evaluated for alignment with expected risk levels.

Note: No saved benchmark results are committed to this repository. Metrics are printed to stdout during training and evaluation runs. To obtain verified numbers, run the training pipeline and evaluate against the generated test split.


💾 Model Artifacts

models/
├── risk_classifier.pkl   — Trained RandomForestClassifier + LabelEncoder classes
├── risk_regressor.pkl    — Trained RandomForestRegressor
├── scaler.pkl            — Fitted StandardScaler (shared by both models)
└── label_encoder.pkl     — LabelEncoder mapping: 0=High, 1=Low, 2=Medium (sklearn alphabetical)

Model .pkl files are excluded from version control via .gitignore. You must run the training pipeline to generate them locally.

The backend's ModelLoader class checks for all four files at startup. If any are missing, it falls back to a rule-based dummy model so the API remains functional without trained artifacts.


⚡ FastAPI Backend

  • Framework: FastAPI 0.128 with Uvicorn
  • CORS: Enabled for all origins (allow_origins=["*"]) — suitable for development; restrict in any production deployment
  • Model loading: On startup via @app.on_event("startup"), with graceful dummy fallback
  • Validation: Pydantic PatientData schema + manual range checks (age 0–120, height 50–250 cm, weight 20–300 kg)
  • Error handling: Per-endpoint HTTPException + global exception handler returning structured JSON
  • Health endpoint: GET /health reports API version and whether real trained models are loaded

📡 API Documentation

FastAPI automatically generates interactive documentation at:

  • Swagger UI: http://localhost:8000/docs
  • ReDoc: http://localhost:8000/redoc

POST /predict

Request body (PatientData):

{
  "age": 45,
  "gender": "Male",
  "height": 175,
  "weight": 80,
  "systolic_bp": 140,
  "diastolic_bp": 90,
  "heart_rate": 75,
  "temperature": 36.6,
  "diabetes": false,
  "hypertension": true,
  "smoking": false,
  "alcohol": false,
  "family_history": true,
  "symptoms": ["chest_pain", "fatigue"],
  "physical_activity": "Medium",
  "sleep_hours": 6,
  "stress_level": 3
}

Valid symptom values: chest_pain, shortness_of_breath, fatigue, headache, fever, frequent_urination

Valid physical_activity values: Low, Medium, High

Response body (PredictionResponse):

{
  "risk_level": "Medium",
  "risk_percentage": 52,
  "explanation": "High blood pressure is a major risk factor. Chest pain indicates potential cardiac issues. High stress levels contribute to health risks.",
  "recommendations": [
    "Monitor and control blood pressure regularly",
    "Achieve and maintain healthy weight through diet and exercise",
    "Improve sleep quality and aim for 7-9 hours nightly",
    "Practice stress management techniques and relaxation",
    "Schedule regular health checkups and screenings"
  ],
  "confidence": 0.74
}
Field Type Description
risk_level string Low, Medium, or High
risk_percentage integer 5–95, combined classifier + regressor estimate
explanation string Up to 3 contributing risk factors in plain language
recommendations array[string] Up to 5 personalized health recommendations
confidence float Max class probability from the classifier (0–1)

GET /health

{
  "status": "ok",
  "models": "real",
  "api_version": "1.0.0"
}

models is "real" when trained .pkl files are loaded, "dummy" otherwise.

Example curl

curl -X POST "http://localhost:8000/predict" \
  -H "Content-Type: application/json" \
  -d '{
    "age": 45,
    "gender": "Male",
    "height": 175,
    "weight": 80,
    "systolic_bp": 140,
    "diastolic_bp": 90,
    "heart_rate": 75,
    "temperature": 36.6,
    "diabetes": false,
    "hypertension": true,
    "smoking": false,
    "alcohol": false,
    "family_history": true,
    "symptoms": ["chest_pain", "fatigue"],
    "physical_activity": "Medium",
    "sleep_hours": 6,
    "stress_level": 3
  }'

💻 Frontend

The frontend is a single-page dashboard (frontend/index.html) built with:

  • Tailwind CSS (CDN) for layout and styling
  • Font Awesome (CDN) for icons
  • Vanilla JavaScript (script.js) for all interactivity

Form Sections

Section Fields
Personal Information Age, Gender (radio), Height (cm), Weight (kg)
Vitals Systolic BP, Diastolic BP, Heart Rate, Body Temperature (°C)
Medical History Diabetes, Hypertension, Smoking, Alcohol, Family History (toggle switches)
Symptoms Searchable dropdown with chip-based multi-select (6 allowed symptoms)
Lifestyle Physical Activity (Low/Medium/High toggle), Sleep Hours (slider), Stress Level (1–5 slider)

Output Panel

  • Risk level badge — color-coded (green/yellow/red) with animated glow
  • Animated circular progress gauge — SVG ring that fills to the risk percentage
  • Explanation text — plain-language summary of top risk factors
  • Recommendations list — up to 5 personalized suggestions
  • Disease probability bars — 5 animated progress bars (Heart Disease, Diabetes, Hypertension, Anemia, Respiratory Risk) derived proportionally from the overall risk percentage

Note: The disease probability bars are visual indicators derived from the overall risk_percentage using a fixed multiplier formula. They are not independent model predictions for each disease.

API Integration

The frontend reads window.API_BASE_URL (set in index.html) which defaults to the deployed Netlify URL. For local development, update window.API_BASE_URL in frontend/index.html to http://localhost:8000.


📁 Project Structure

Medical-Risk-Disease-Prediction-System/
│
├── backend/
│   ├── main.py                  # FastAPI app, routes, CORS, startup
│   ├── schemas.py               # Pydantic models: PatientData, PredictionResponse
│   ├── feature_engineering.py   # Feature extraction, explanation, recommendations
│   ├── prediction.py            # Inference pipeline + medical rule overrides
│   ├── model_loader.py          # ModelLoader class with dummy fallback
│   ├── config.py                # Paths, thresholds, symptom weights
│   ├── requirements.txt         # Backend-specific dependency list
│   └── __init__.py
│
├── frontend/
│   ├── index.html               # Single-page dashboard (Tailwind CSS)
│   ├── script.js                # Form logic, API calls, UI updates
│   └── style.css                # Custom CSS (animations, toggle switches)
│
├── data/
│   ├── patient_data_balanced.csv  # Generated balanced dataset (1,500 samples)
│   └── patient_data.csv           # Original dataset
│
├── models/                        # Trained model artifacts (git-ignored)
│   ├── risk_classifier.pkl
│   ├── risk_regressor.pkl
│   ├── scaler.pkl
│   └── label_encoder.pkl
│
├── training/
│   ├── create_balanced_dataset.py # Synthetic dataset generator (1,500 balanced samples)
│   ├── train_classifier.py        # RandomForestClassifier training + evaluation
│   ├── train_regressor.py         # RandomForestRegressor training + evaluation
│   ├── train_all_models.py        # Full pipeline: dataset → classifier → regressor → validation
│   ├── train_models.py            # Alternate combined training script
│   ├── evaluate.py                # Cross-validation, metrics, medical relevance tests
│   └── __init__.py
│
├── .env                           # Local environment variables (git-ignored)
├── .gitignore
├── LICENSE                        # MIT License
├── Procfile                       # Render/Heroku-style deployment command
├── requirements.txt               # Full project dependencies
└── README.md

🛠️ Tech Stack

Backend

Technology Version Purpose
Python 3.x Runtime
FastAPI 0.128 REST API framework
Uvicorn 0.40 ASGI server
Pydantic 2.x Request/response validation
python-dotenv 1.2 Environment variable loading

Machine Learning

Technology Version Purpose
scikit-learn 1.8 RandomForest models, StandardScaler, LabelEncoder
NumPy 2.x Numerical operations, feature arrays
Pandas 2.x Dataset loading and manipulation
joblib 1.5 Model serialization

Frontend

Technology Purpose
HTML5 Page structure
Tailwind CSS (CDN) Utility-first styling
Font Awesome (CDN) Icons
Vanilla JavaScript Form logic, API calls, animations

Deployment

Technology Purpose
Netlify Frontend hosting
Render (configured) Backend API hosting via Procfile

📋 Prerequisites

  • Python 3.8 or higher
  • pip
  • A virtual environment tool (recommended)

🚀 Installation

1. Clone the repository

git clone https://github.com/SadiqCodex/Medical-Risk-Disease-Prediction-System.git
cd Medical-Risk-Disease-Prediction-System

2. Create and activate a virtual environment

Windows:

python -m venv venv
venv\Scripts\activate

Linux / macOS:

python3 -m venv venv
source venv/bin/activate

3. Install dependencies

pip install -r requirements.txt

🧪 Model Training

Run the full training pipeline in order:

Option A — All-in-one script (recommended):

python training/train_all_models.py

This generates the balanced dataset, trains both models, and runs validation test cases.

Option B — Step by step:

# Step 1: Generate the balanced synthetic dataset (1,500 samples)
python training/create_balanced_dataset.py

# Step 2: Train the Random Forest Classifier
python training/train_classifier.py

# Step 3: Train the Random Forest Regressor
python training/train_regressor.py

# Step 4: Run evaluation (cross-validation, metrics, medical relevance tests)
python training/evaluate.py

train_classifier.py must run before train_regressor.py because the regressor reuses the scaler saved during classifier training.

Trained artifacts are saved to models/:

  • risk_classifier.pkl
  • risk_regressor.pkl
  • scaler.pkl
  • label_encoder.pkl

▶️ Running the Application

Start the backend

cd backend
uvicorn main:app --reload --host 0.0.0.0 --port 8000

The API will be available at http://localhost:8000. Interactive docs: http://localhost:8000/docs

Open the frontend

The frontend is a static HTML file. Open it directly in a browser:

frontend/index.html

Or serve it via a local HTTP server to avoid CORS issues:

cd frontend
python -m http.server 3000

Then open http://localhost:3000 in your browser.

For local development, update window.API_BASE_URL in frontend/index.html to http://localhost:8000.


🌐 Deployment

The frontend is deployed on Netlify: medical-risk-predictor.netlify.app

The backend is configured for Render or Heroku-style platforms via Procfile:

web: uvicorn backend.main:app --host 0.0.0.0 --port $PORT

To deploy the backend:

  1. Push the repository to GitHub
  2. Connect to Render (or equivalent)
  3. Set the start command from the Procfile
  4. Ensure trained model .pkl files are either committed (after removing them from .gitignore) or regenerated as part of a build step

Model files are currently excluded from version control. A deployment strategy that regenerates models at build time or stores them in persistent storage is required for a live deployment.


🔒 Security & Privacy

  • Input validation is enforced at both the API layer (Pydantic + range checks) and the frontend (JavaScript)
  • No patient data is stored, logged, or persisted — all predictions are stateless
  • Environment variables are managed via .env (excluded from version control via .gitignore)
  • CORS is currently open (allow_origins=["*"]); this should be restricted to specific origins in any non-local deployment
  • No authentication or authorization is implemented in the current version

⚠️ Limitations

  • Synthetic dataset: The training data is algorithmically generated with fixed statistical ranges. It does not represent real patient populations and may not generalize to real-world clinical data.
  • No clinical validation: The models have not been tested against real patient outcomes or validated by medical professionals.
  • Heuristic features: The 7 engineered features and the medical rule overrides are hand-crafted heuristics, not evidence-based clinical scoring systems.
  • Limited feature set: Heart rate and body temperature are collected but not used in the current feature engineering pipeline.
  • Disease probability bars: The five disease indicators in the frontend are derived from the overall risk percentage using a fixed formula — they are not independent model predictions.
  • No uncertainty quantification: Beyond the classifier's max class probability, the system does not provide calibrated confidence intervals.
  • No model monitoring: There is no drift detection, logging, or performance monitoring in the current implementation.
  • Open CORS: The API accepts requests from any origin, which is not appropriate for production.

⚠️ Ethical & Medical Disclaimer

This project is an educational and research-oriented machine-learning prototype. It is intended for software and ML demonstration purposes only.

  • Predictions produced by this system are algorithmic estimates based on a synthetic dataset and do not constitute medical diagnoses.
  • This system is not a substitute for consultation with a qualified healthcare professional.
  • Outputs should not be used as the sole basis for any medical, clinical, or treatment decision.
  • The synthetic training data does not represent real patient records and carries no clinical validity.
  • Real-world clinical deployment of any risk prediction system would require extensive prospective validation, regulatory review (e.g., FDA, CE marking), patient privacy protections (e.g., HIPAA, GDPR), and ongoing medical oversight — none of which are present in this project.
  • The author makes no warranty regarding the medical accuracy, completeness, or fitness for clinical use of this system.

🔮 Future Improvements

[ ] Replace synthetic dataset with a validated public clinical dataset
[ ] Add SHAP values for per-prediction feature importance explanations
[ ] Incorporate heart rate and body temperature into feature engineering
[ ] Implement independent per-disease prediction models
[ ] Add hyperparameter optimization (GridSearchCV / Optuna)
[ ] Add ROC-AUC, calibration curves, and precision-recall analysis
[ ] Implement model versioning and experiment tracking (MLflow)
[ ] Add authentication and rate limiting to the API
[ ] Restrict CORS to specific origins
[ ] Add Docker support for reproducible deployment
[ ] Implement CI/CD pipeline with automated evaluation
[ ] Add comprehensive automated tests (pytest)
[ ] Improve frontend UX with better mobile responsiveness
[ ] Add database integration for optional session logging

🤝 Contributing

Contributions are welcome. Please follow this workflow:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/your-feature)
  3. Make your changes
  4. Run the training pipeline and evaluate model performance
  5. Commit with a clear message (git commit -m "Add: description")
  6. Push to your fork and open a Pull Request

Please do not introduce unverified medical claims or fabricated performance metrics.


📄 License

This project is licensed under the MIT License. See LICENSE for details.


👨💻 Author

Sadik Mohammad

GitHub: @SadiqCodex


Live Demo

This project is a machine-learning portfolio prototype. It is not intended for clinical use.

Releases

Packages

Contributors

Languages