← All work

PAD Detection + Risk Copilot

Two halves of one project: a machine learning pipeline that predicts peripheral artery disease (PAD) from routine hospital data, and a RAG copilot that turns each prediction into an explanation a reader can check.

Area
Health · RAG
Stack
Python, scikit-learn, XGBoost, LightGBM, SHAP, Ollama, Streamlit
Links
GitHub
PAD Risk Copilot: a PAD probability, the top SHAP factors as bars, and a written explanation citing numbered NHLBI and CDC passages
The copilot explaining a demo record with numbered citations. The model shown here was trained on synthetic test data.

Problem

The pipeline predicts PAD from data a hospital already collects: labs, demographics, comorbidities and medications. The copilot answers why this score? with SHAP attributions and cited passages from public clinical references.

Users

Researchers and clinicians reviewing a risk score, for research use only. This is not a medical device and has not been validated prospectively or externally.

Constraints

  • Data use agreement. MIMIC-IV values cannot be sent to a third party under the PhysioNet agreement, so the language model runs locally through Ollama and no API is used.
  • Hardware. Both models (llama3.1:8b and nomic-embed-text) have to fit together on an 8 GB GPU.
  • Noisy label. The label is a billing code, which can miss or mislabel patients, and MIMIC-IV is an ICU population, sicker than the general public.
  • Missing signals. There is no ankle-brachial index, no smoking status and no imaging in these tables.

What I built

The model. A matched case-control cohort from MIMIC-IV, 13 engineered features (demographics, labs, comorbidities, medications) and six classifiers: logistic regression, random forest, SVM, MLP, XGBoost and LightGBM. The winner is chosen by grouped 5-fold cross-validation and scored once on a held-out test set.

Leakage controls, each covered by a test that was checked to fail against the earlier behaviour:

  • Patient-level cohort and split, so no one appears as both a case and a control, or in both train and test.
  • Comorbidities and medications come only from strictly earlier admissions. Statins are the standard PAD treatment, so counting them from the index stay would leak the diagnosis.
  • Controls matched 1:1 on age bracket × gender, so the model has to learn something clinical.
  • Drug names are matched exactly. A bare statin substring would also match nystatin, an antifungal.

The copilot. It scores the record, computes SHAP attributions, retrieves passages from an index of NHLBI and CDC pages plus a model card, asks a local LLM to explain citing those passages, then verifies every citation in code. Any [n] that doesn't resolve to a retrieved passage is stripped and flagged. There's a Streamlit UI on top.

Metrics

MeasureResult
Best model AUC0.88
Retrieval hit@6 (24-question golden set)24/24
Retrieval hit@119/24
Citations valid (no unresolvable citation survived)24/24
Answers citing a source22/24
Empty answers0/24
Automated tests (synthetic MIMIC-shaped fixture)54

The two answers without a citation are marked as ungrounded in the UI.

Trade-offs I made

  • A local 8B model.The data agreement rules out hosted models, so the copilot runs llama3.1:8b locally. Its answers are weaker, which is one reason citations are checked in code.
  • The copilot can decline to answer.If no passage clears the relevance threshold, the LLM is never called and the copilot says so.
  • The test embedder must be asked for by name.An offline hashing embedder exists for tests. It scores 0.79 / 0.54 (hit@6 / hit@1) against 1.00 / 0.79 for real embeddings, so it is never swapped in automatically.
  • SHAP factors are worded as score movement.Given "statin therapy increases", the model once wrote that statins increase PAD risk. Factors are now phrased as "pushed the score up/down".
  • Only prior admissions for comorbidities and medications.This gives up some signal to avoid leaking the diagnosis into the features.

What I'd do next

  • Calibrate the probabilities (Platt or isotonic). Matched controls change the base rate, so today's scores rank patients well but need calibrating before they can be read as probabilities.
  • Rerank retrieved passages before generation.
  • Add features from MIMIC-IV-Note clinical notes, such as smoking status and mentions of claudication.