Repository navigation
PyHealth 2.1.0 focuses on making results trustworthy: leakage-free preprocessing with split-aware set_task, reproducible training, and calibration metrics with patient-level confidence intervals. It also adds an XGBoost model with exact TreeSHAP, Synthea synthetic-patient generation, ICD-9 ↔ ICD-10 translation, and a nine-notebook tutorial series.
pip install -U pyhealth==2.1.0
pip install -U "pyhealth[xgboost]==2.1.0" # with XGBoostModelWarning
Rebuild caches built with more than 10 workers. Before this release, set_task with more than 10 workers could misorder its sample index, so patient-level splits shared patients between train and val/test (on full MIMIC-IV with 32 workers, ~3.6k patients). 2.1.0 fixes this, but caches built that way are still reused as-is. Delete them and rebuild. (#1273)
Before you upgrade
- Dependencies:
- Requires
torch>=2.10,pyarrow>=23.0.1,dask[complete]>=2026.1.0andlitdata>=0.2.64,<0.2.68. (#1254, #1273) - numpy, pandas, pydantic, scikit-learn and narwhals use bounded ranges, so installs on Google Colab no longer downgrade packages it has already loaded. (#1287)
icd-mappingsis a new dependency;urllib3is no longer one. (#1257, #1254)
- Requires
- EHR-generation tasks: the
EHRGenerationbase class is removed and there is one task per encoding and dataset (#1233):EHRGenerationMIMIC3/4: per-visit multi-hot rows, for HALO. These now emitnested_multihotinstead ofnested_sequence.EHRSequenceGenerationMIMIC3/4: per-visit code indices, for GPT-2 and PromptEHR.EHRCodeSetGenerationMIMIC3/4: one code set per patient, for MedGAN and CorGAN.
Eventtimestamps: a missing timestamp is nowNone. It used to bedatetime.now(), which sorted before every real event and slipped through time-window filters. (#1247)- Caches: dataset and sample caches rebuild once on first use, because their cache keys changed. Old cache folders stay on disk and can be deleted. (#1265, #1277)
- Shuffles and splits: runs are now reproducible from a seed, but the same seed selects different batches and patients than in 2.0.2. (#1280, #1286)
- Logging: the
pyhealthlogger no longer propagates to the root logger, so each message prints once in Jupyter and Colab. (#1285) - Default cache location: building a dataset without
cache_dirlogs a warning naming the folder it writes to. SetPYHEALTH_REQUIRE_CACHE_DIR=1to make it an error. (#1264) - Removed: the unmaintained 2023
chat-assistant/demo. (#1252)
New features
- Split-aware preprocessing (#1273):
dataset.set_task(task, split=PatientSplit(...))fits every processor on the training patients only and returns(train, val, test)views of one processed cache.PatientSplittakes two or more ratios, for example train/val/calibration/test.- Custom splits implement the new
Splitinterface. - Processors that learn statistics warn when they are fitted on all samples.
- Reproducible training (#1280):
get_dataloader(..., seed=...)gives each loader its own seeded, per-epoch shuffle, in memory and on disk.torch.manual_seedalone now makes runs repeatable.- New
pyhealth.utils.preserve_rng_state().set_task, dataset creation and the interpretability methods no longer change global random state, and importingpyhealth.modelsno longer reseeds numpy and torch. Trainer.trainrestores the best epoch even with logging off (keep_best_in_memory).
- Calibration and confidence intervals (#1268):
binary_metrics_fnaddsbrier,oe_ratio,calibration_slopeandcalibration_intercept.- New
pyhealth.metrics.bootstrapwithbootstrap_ciandpaired_bootstrap_diff. Passgroups=to resample whole patients.
- Imbalanced outcomes:
BaseModel.set_pos_weight(...)takes a number, one number per label, or"balanced"computed from a training dataset. (#1267) XGBoostModel(#1278):- Gradient-boosted trees for binary, multiclass, multilabel and regression tasks.
- Train with
model.fit(train, val=None), then evaluate with the usualTrainer. - Accepts tensor, timeseries, multi-hot and nested multi-hot inputs;
bag_of_codes=Trueturns code sequences into per-patient code counts. - Supports
scale_pos_weightand early stopping. - Exact TreeSHAP through
explain()and the newpyhealth.interpret.methods.TreeSHAP.
- Synthea (#1244):
pyhealth.models.Synthearuns the Synthea synthetic-patient generator. It needs Java 17+ and downloads and caches the Synthea JAR.SyntheaCSVDatasetloads Synthea's CSV output.
- Medical codes (#1257):
CrossMaptranslates ICD-9 ↔ ICD-10 and maps codes to CCSR categories, chapters and blocks, and chronic-condition indicators, using theicd-mappingspackage.- Existing mappings such as ICD9CM → CCSCM are unchanged.
- ICD-9 ↔ ICD-10 follows each code's primary mapping only, so some codes map to nothing or don't round-trip. Those are reported through a warning and
CrossMap.unmapped_codes.
- Processors:
- HALO: visit encoding is vectorised, removing a loop that took ~85% of each training step on GPU. (#1233)
Fixes
- Leakage and labels:
MultimodalMortalityPredictionMIMIC4used chest X-rays taken after the prediction time. (#1229)T1DDKAPredictionMIMIC4counted DKA events recorded before a separate T1DM diagnosis. (#1230)- Patient-level splits with more than 10 workers mixed patients across parts (see the warning above). (#1273)
- Supplying fitted processors for only some fields left the others unprocessed. (#1273)
- Datasets and caching:
- Editing a source file or the dataset's YAML config reused the stale cache. (#1265)
- Sample fields whose length varies between samples failed or were misread on the disk cache. (#1277)
- Visits longer than the fitted width produced batches with mismatched widths; they are now truncated with a warning. (#1263)
Eventobjects could not be copied or unpickled. (#1247)- Each dataset build leaked file descriptors, causing "Too many open files" on macOS. (#1245)
- Interrupted downloads left truncated files that later runs reused, and stalled downloads hung. (#1255)
- Patient splitters chose different patients for the same seed depending on sample order. (#1286)
- Models:
- Interpretability: comprehensiveness and sufficiency crashed for every model with code-sequence inputs. (#1284)
Docs, examples and infrastructure
- Nine-notebook tutorial series under
examples/tutorials/series/, from a first model to contributing, each runnable on a CPU Colab runtime. (#1281) - New docs sections and example scripts for reproducible runs, split-aware
set_task, reusing fitted processors, imbalanced outcomes, calibration and bootstrap CIs, cache behaviour, identified data, and logging setup. SECURITY.mddescribes private vulnerability reporting and which files must come from trusted sources. (#1253)- Dependency minimums were raised past known security issues; pip-audit reports none on a fresh install. (#1254)
- CI now reports test coverage. (#1299)
See CHANGELOG.md for full details on every change.
Full Changelog: v2.0.2...v2.1.0