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.
- Overview
- Key Features
- System Architecture
- How It Works
- Medical Feature Engineering
- Dataset
- Machine Learning Models
- Model Evaluation
- Model Artifacts
- FastAPI Backend
- API Documentation
- Frontend
- Project Structure
- Tech Stack
- Prerequisites
- Installation
- Model Training
- Running the Application
- Deployment
- Security & Privacy
- Limitations
- Ethical & Medical Disclaimer
- Future Improvements
- Contributing
- License
- Author
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.
Predicts one of three categorical risk levels — Low, Medium, or High — using a trained Random Forest Classifier with probability-based inference.
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%).
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
A post-prediction rule layer applies medical heuristics to override ML outputs in clearly healthy or clearly high-risk profiles, improving clinical plausibility.
The system generates a plain-language explanation of the top contributing risk factors and up to 5 personalized health recommendations per prediction.
RESTful API with Pydantic input validation, CORS support, startup model loading, graceful fallback to dummy models, and a /health endpoint.
A Tailwind CSS dashboard with a patient input form, animated risk gauge, progress bars for disease probability indicators, and real-time API integration.
Both backend (Pydantic schema + manual range checks) and frontend (JavaScript form validation) validate inputs before any prediction is made.
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
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
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 |
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%
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 |
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.
| 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.
| 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_risk_percentage = (classifier_probability_percentage × 0.7) + (regressor_prediction × 0.3)
Clipped to [5, 95] before medical rule overrides are applied.
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.
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
.pklfiles 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.
- 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
PatientDataschema + 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 /healthreports API version and whether real trained models are loaded
FastAPI automatically generates interactive documentation at:
- Swagger UI:
http://localhost:8000/docs - ReDoc:
http://localhost:8000/redoc
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) |
{
"status": "ok",
"models": "real",
"api_version": "1.0.0"
}models is "real" when trained .pkl files are loaded, "dummy" otherwise.
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
}'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
| 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) |
- 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_percentageusing a fixed multiplier formula. They are not independent model predictions for each disease.
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.
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
| 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 |
| 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 |
| Technology | Purpose |
|---|---|
| HTML5 | Page structure |
| Tailwind CSS (CDN) | Utility-first styling |
| Font Awesome (CDN) | Icons |
| Vanilla JavaScript | Form logic, API calls, animations |
| Technology | Purpose |
|---|---|
| Netlify | Frontend hosting |
| Render (configured) | Backend API hosting via Procfile |
- Python 3.8 or higher
- pip
- A virtual environment tool (recommended)
git clone https://github.com/SadiqCodex/Medical-Risk-Disease-Prediction-System.git
cd Medical-Risk-Disease-Prediction-SystemWindows:
python -m venv venv
venv\Scripts\activateLinux / macOS:
python3 -m venv venv
source venv/bin/activatepip install -r requirements.txtRun the full training pipeline in order:
Option A — All-in-one script (recommended):
python training/train_all_models.pyThis 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.pymust run beforetrain_regressor.pybecause the regressor reuses the scaler saved during classifier training.
Trained artifacts are saved to models/:
risk_classifier.pklrisk_regressor.pklscaler.pkllabel_encoder.pkl
cd backend
uvicorn main:app --reload --host 0.0.0.0 --port 8000The API will be available at http://localhost:8000.
Interactive docs: http://localhost:8000/docs
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 3000Then open http://localhost:3000 in your browser.
For local development, update
window.API_BASE_URLinfrontend/index.htmltohttp://localhost:8000.
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:
- Push the repository to GitHub
- Connect to Render (or equivalent)
- Set the start command from the Procfile
- Ensure trained model
.pklfiles 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.
- 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
- 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.
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.
[ ] 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
Contributions are welcome. Please follow this workflow:
- Fork the repository
- Create a feature branch (
git checkout -b feature/your-feature) - Make your changes
- Run the training pipeline and evaluate model performance
- Commit with a clear message (
git commit -m "Add: description") - Push to your fork and open a Pull Request
Please do not introduce unverified medical claims or fabricated performance metrics.
This project is licensed under the MIT License. See LICENSE for details.
Sadik Mohammad
GitHub: @SadiqCodex