Biliary Tract Cancer Early Detection
A production model that flags likely BTC patients ~45 days before claims data confirms them — scoring 250M patient-claims every month.
- Org
- ZS Associates — Fortune-500 oncology client
- Role
- Advanced Data Science Associate Consultant
- Period
- 2024 — 2025
- Status
- production
- Stack
- PySpark · XGBoost · SHAP · K-means / GMM · NLP clustering · MLflow
The problem
Biliary tract cancer (BTC) is a rare cancer with very few approved treatments. The client's oncology drug — a new standard of care for BTC — had to be given as the first treatment after diagnosis; switching later was not an option. But because BTC is rare and presents with non-specific symptoms, patients are routinely misdiagnosed first, and once BTC is correctly identified, treatment starts almost immediately.
That left a brutally narrow window: to matter at all, the right oncologists had to be educated before the diagnosis showed up anywhere in the data.
The constraints
The medical and pharmacy claims data available had a consistent 45-day delay from real-world events. By the time a patient appeared in the data, treatment had usually already started. On top of the lag:
- Severe class imbalance — BTC is extremely rare
- Noisy, incomplete claims capture (~50% of real-world claims)
- High risk of temporal leakage if future information contaminated earlier predictions
- Tens of millions of rows across hundreds of thousands of patients, refreshed monthly
The loop
We framed it as a time-indexed prediction task: for each patient-month, estimate the probability of a BTC diagnosis in the next 30 days.
To reduce ~250M patient records per month to a modelable subset, three filters worked in sequence:
- Direct rule-based filtering on diagnosis and procedure flags
- K-means and Gaussian-mixture clustering over patient utilization patterns
- NLP-based event clustering of claim sequences, to find patients whose journeys resembled known BTC trajectories even without the telltale codes
The critical discipline: we masked the most recent 45 days of data before every index date, so the model trained and validated under exactly the information conditions it would face live. No leakage, no flattering backtest.
The build
XGBoost with class-weighted loss handled the imbalance. Features covered diagnosis codes, procedures, drug regimens, provider patterns, and utilization metrics.
Two things made it survivable in production rather than a slide-deck model:
- SHAP explanations on every score, so non-technical stakeholders (and skeptical clinicians) could see why a patient was flagged
- MLflow versioning and drift monitoring, with the pipeline productionized to process each monthly claims refresh automatically and expose outputs through summary tables and dashboards used directly by field teams
Evidence
The ~45-day advantage is measured against the claims-lag baseline under the masked-data protocol — the model never saw information it wouldn't have had in production.
- Substantial lift in early BTC identification versus the heuristic rules it replaced
- Clinician-acceptable precision, with interpretable per-patient feature effects via SHAP
- Feature and prediction drift monitored across monthly refreshes — silent failure was a design concern, not an afterthought
Impact
- Field teams used model outputs for territory-level resource planning
- Positive feedback from marketing teams on practical usefulness
- The client funded replication of the approach across other tumors and brands
- Methodology presented at PMSA 2025
Questions about this project? Press ⌘K — the chat answers from these case studies and cites them.