--- license: mit library_name: sklearn pipeline_tag: tabular-classification tags: - lightgbm - random-forest - shap - cardiovascular - tabular - sulianova widget: - structuredData: {"age": [56.0], "gender": [1.0], "height": [152.0], "weight": [72.0], "ap_hi": [160.0], "ap_lo": [90.0], "cholesterol": [3.0], "gluc": [1.0], "smoke": [0.0], "alco": [0.0], "active": [1.0]} example_title: Sample patient model-index: - name: kiselyovd/cardio-risk-rf results: - task: type: tabular-classification name: Cardiovascular disease presence dataset: type: sulianova/cardiovascular-disease-dataset name: sulianova Cardiovascular Disease Dataset metrics: - type: roc_auc value: 0.798 - type: pr_auc value: 0.784 - type: f1 value: 0.717 - type: brier value: 0.1822 --- # cardio-risk-rf

cardio-risk-rf - tabular cardiovascular-risk classification

Production-grade tabular cardiovascular-disease classifier on the [sulianova Cardiovascular Disease Dataset](https://www.kaggle.com/datasets/sulianova/cardiovascular-disease-dataset) (70 000 patients, 11 clinical features, balanced 50/50 target `cardio`). The main artefact is `cardio_risk_lgbm.joblib` (LightGBM, Optuna-tuned, native NaN handling); the baseline is `cardio_risk_rf.joblib` (RandomForest with median imputation). Both are scikit-learn `Pipeline` objects you load with `joblib` and call `predict_proba` on. ![ROC and Precision-Recall curves](plots/roc_pr.png) *ROC and Precision-Recall curves on the held-out test split (n=10 501, balanced). LightGBM (main) vs RandomForest (baseline), AUROC / PR-AUC computed from real predictions.* ## Metrics Held-out test split (n=10 501, balanced target). Values are computed from real `predict_proba` outputs; F1 is reported at both the default 0.5 threshold and at the validation-set F1-optimal threshold t\*. | Model | ROC-AUC | PR-AUC | F1 @ 0.5 | F1 @ t\* | Brier | t\* | |---|---|---|---|---|---|---| | **LightGBM** (main) | **79.8%** | **78.4%** | 71.7% | **73.9%** | 0.182 | 0.35 | | RandomForest (baseline) | 79.5% | 77.9% | 70.8% | 73.2% | 0.184 | 0.41 | A balanced 50/50 target means the no-skill baseline is 50% for both ROC-AUC and PR-AUC, so both models add roughly 28-30 points of real signal. LightGBM edges out the RandomForest baseline on every metric while staying well calibrated (Brier 0.182). ## Visualizations The ROC and Precision-Recall curves are shown at the top of this card. The two plots below cover calibration and feature attribution. ### Calibration ![Calibration curve](plots/calibration.png) Reliability curve of the LightGBM main model on the validation split (10 bins). Predicted probabilities track the diagonal closely, so the scores are usable as risk estimates rather than just rankings. ### SHAP feature importance ![SHAP summary](plots/shap_summary.png) Global SHAP summary for the LightGBM main model. Systolic blood pressure (`ap_hi`) dominates, followed by age and cholesterol, matching clinical intuition. ## Feature order (11) `age (years), gender (1=female, 2=male), height (cm), weight (kg), ap_hi (systolic BP mmHg), ap_lo (diastolic BP mmHg), cholesterol (1=normal, 2=above, 3=well-above), gluc (1-3 same scale), smoke (0/1), alco (0/1), active (0/1)`. Any field may be `null` - LightGBM handles NaN natively; the RandomForest pipeline imputes with the training-set median. Input is coerced to `float` at serve-time. ## Top SHAP drivers (global, on validation) 1. `ap_hi` (systolic blood pressure) - dominant 2. `age` 3. `cholesterol` 4. `weight` 5. `ap_lo` ## Usage ```python from huggingface_hub import hf_hub_download import joblib, pandas as pd path = hf_hub_download(repo_id="kiselyovd/cardio-risk-rf", filename="cardio_risk_lgbm.joblib") model = joblib.load(path) x = pd.DataFrame([{"age": 56.0, "gender": 1.0, "height": 152.0, "weight": 72.0, "ap_hi": 160.0, "ap_lo": 90.0, "cholesterol": 3.0, "gluc": 1.0, "smoke": 0.0, "alco": 0.0, "active": 1.0}]) print(model.predict_proba(x)) ``` ## Intended use Educational artifact demonstrating a production-grade tabular ML pipeline (LightGBM + SHAP + FastAPI + Docker + HF Hub). **Not a medical device.** Do not use it for clinical decisions. The `cardio` target is cross-sectional (presence at examination), not a prospective 10-year risk. ## Source and license Code, training pipeline and full docs: [github.com/kiselyovd/cardio-risk-rf](https://github.com/kiselyovd/cardio-risk-rf). Released under the MIT License. Dataset: sulianova Cardiovascular Disease Dataset.