Bayesian logistic regression classifier for cardiovascular risk prediction, built with NumPyro and JAX. Provides per-prediction uncertainty estimates via posterior sampling (NUTS/MCMC).
- Model — NumPyro (NUTS sampler), JAX
- Preprocessing — scikit-learn pipeline, Pydantic validation
- API — FastAPI + Uvicorn
- Frontend — React + Vite (TypeScript), served via nginx
src/
esitmator/ # BayessianClassifier (fit, predict, predict_proba, predict_uncertainty)
models/ # NumPyro model definition, PatientRecord Pydantic schema
preprocessing/ # Preprocessor (StandardScaler + OneHotEncoder pipeline)
server/ # FastAPI app + Dockerfile
frontend/ # React + Vite frontend + Dockerfile + nginx.conf
data/ # Training data (NSH_clear.csv)
docker-compose.yml # Compose: server (8000) + frontend (80)
fit_model.py # Train and evaluate, saves figures/evaluation.png
Nigeria Smoking & Health — somtoonkannebe
3 900 patient records from Nigeria with demographic, haematological, and cardiovascular features. Target variable is cardio_risk, derived from blood pressure, cholesterol, and heart rate thresholds.
Requires uv.
uv syncuv run python fit_model.pySaves figures/evaluation.png with confusion matrix, ROC curve, and uncertainty distribution.
uv run uvicorn src.server.server:app --host 0.0.0.0 --port 8000http://localhost:8000/health— health check (GET)http://localhost:8000/predict— REST endpoint (POST)http://localhost:8000/docs— Swagger UI
cd frontend && npm install && npm run devhttp://localhost:5173— React dev server (proxies/predictto port 8000)
just run # build and start both services
just down # stop and remove containershttp://localhost— frontend (nginx)http://localhost:8000— API
POST /predict
{
"age": 45,
"sex": 1,
"cigs_per_day": 0,
"sickle_cell_genotype": "AA",
"malaria_exposure": 0.0,
"hemoglobin_g_per_dL": 13.5,
"heart_rate_bpm": 78,
"cholesterol_mg_per_dL": 245.0,
"blood_pressure_upper": 145.0,
"blood_pressure_lower": 92.0
}Response:
{
"prediction": 1,
"probability": 0.81,
"uncertainty": {
"mean": 0.81,
"std": 0.09,
"lower": 0.63,
"upper": 0.94
}
}sex: 0 = female, 1 = male
malaria_exposure: 0.0 = rare, 0.5 = recent, 1.0 = chronic
