Changelog
All notable changes to PyHealth are documented here. Versions follow the
major.minor.patch scheme; see the
releases page for the
corresponding tags and wheels.
2.0.2 — 2026-09-02
The first release since 2.0.1 (2026-03-30). It adds four datasets, a synthetic-EHR
generation and evaluation stack, several new models and interpretability methods, and
a large batch of correctness fixes across models, tasks, metrics, and calibration.
No public API was removed or renamed — 2.0.1 code continues to work unchanged.
New datasets
- MEDS —
MEDSDatasetplus a typed Parquet scan path onBaseDataset..parquet
/.pqfiles, globs, and directories now route through a typed_scan_parquet
scanner, with a datetime fast path that skips the string round-trip. Includes the
in_hospital_mortality_medstask. (#1179) - FHIR — a full FHIR pipeline under
pyhealth/datasets/fhir/, including a
MIMIC-IV-on-FHIR dataset. (#1155) - EEGBCI — dataset, helper functions, and tasks. (#1177)
- PhysioNet De-Identification — dataset, NER task (
deid_ner), and the
TransformerDeIDmodel. (#981)
New models
- MedFuse — multi-modal fusion of EHR time series with chest X-rays. (#1003)
- Synthetic EHR generators —
pyhealth/models/generators/: HALO, MedGAN, CorGAN,
PromptEHR, and a GPT-2 generator, with thegenerate_ehrtask. (#1148) - CaliForest — calibrated random forest; requires an explicit
fitbefore
inference. (#999) - GRASP — migrated from the 1.x API to 2.0, with
static_keysupport for
demographic features. (#905)
New tasks and metrics
DrugRecommendationOMOP— a class-based OMOP drug recommendation task. (#1203)- Generative evaluation metrics —
pyhealth/metrics/generative/scores synthetic
EHR data on privacy (NNAAR, membership inference, discriminator privacy), utility,
and statistical fidelity. (#1148) - Attention rollout — interpretability method of Abnar & Zuidema (2020). (#1158)
- Conformal prediction — real Adaptive Prediction Sets (Romano, Sesia & Candès
2020) in the newpyhealth/calib/predictionset/scores.py, with a dynamic
score_typeon conformal methods (#1189),
plus additional conformal methods and example scripts (#942).
Restored from 1.x
code_mapping—SequenceProcessoraccepts an optionalcode_mappingthat
collapses granular codes into grouped vocabularies (ICD9CM→CCSCM, ICD9PROC→CCSPROC,
NDC→ATC) before building the embedding table, andBaseTask.__init__accepts it
directly so schemas no longer have to be patched by hand. Closes the functional gap
left by the 1.x→2.0 rewrite. (#905, ref #535)
Fixes
Data leakage and label correctness
- StageNet MIMIC-IV mortality/LOS tasks leaked post-outcome information: diagnosis and
procedure codes are timestamped atdischtime, so for the admission being predicted
they are only known at or after the outcome, and labs were pulled through
discharge/death. Those codes are now excluded for that admission and its labs capped
to the first 48 hours. (#1205) drug_recommendation_omop_fnnever excluded the current visit's own drugs from
drugs_all, making the last history entry identical to the prediction target. (#1203)- Drug tasks extracted
event.drug(drug names, e.g. "Aspirin"), which produce zero
matches in the NDC→ATC CrossMap; they now extractevent.ndc. (#905) - Drug recommendation NDC/ATC3 code handling and padding behaviour. (#1138)
Models
CNNcrashed on 1-D tensor and multi-hot inputs:forwardhardcoded a 3-D
expectation forspatial_dim=1, butMultiHotProcessorand 1-DTensorProcessor
inputs embed to[batch, embedding_dim]with no sequence axis. Now treated as a
length-1 sequence. (#1208)TCNcrashed on tuple-schema features by passing raw kwargs (including
StageNetProcessor's(time, value)tuples) to the embedding model; it now unwraps
thevaluetensor first, like its sibling sequence models. (#1212)BIOThardcodednn.Embedding(n_channels, 256)for channel tokens, crashing for
anyemb_size != 256. (#1213)MoleRec's no-SMILES fallback predictor was created lazily insideforward, so an
optimizer built frommodel.parameters()beforehand never saw its parameters and it
never trained. It is now created in__init__. (#1214)SdohClassifierwas annn.Moduledecorated with@dataclass, whose generated
__init__never callednn.Module.__init__, leaving the module without
_parameters/_modulesand unusable in torch. (#1209)SinusoidalTimeEmbeddingdivided frequency indices byhalf - 1, sodim=2gave
0/0 and every embedding was NaN. Clamped to at least 1. (#1216)- Sparsemax in
AdaCare. (#1139) RNNLayerandConCarecrashed on zero-length sequences and onbatch_size=1;
GRASPcollapsed its hidden state atbatch_size=1and raised when
cluster_num > batch_size. (#905)- MedLink:
collate_fnbuilt output keys from only the first sample in a batch, so a
batch mixing samples with and without a mined hard negative (s_n) either raised
KeyErroror silently produced a misaligned list; keys are now unioned across the
batch. (#1222) - MedLink BM25 hard-negative mining did not preserve all positives. (#1195)
Datasets and tasks
- Patient merging crashed on tables with null
patient_id. (#1193) SampleDatasetsubset mappings were wrong. (#1211)PatientLinkageMIMIC3Task'sinput_schemanamed"integer"/"string"/
"datetime"processors, none of which are registered, soset_task()failed
immediately withValueError: Unknown processor. (#1204)
Metrics, calibration, and interpretability
ece_confidence_binaryindexedprob[:, 0]/label[:, 0], requiring 2-D arrays,
but its only caller passes 1-D positive-class probabilities and 1-D 0/1 labels — so
ECEandECE_adaptalways raisedIndexErroron binary tasks. (#1215)disparate_impactandstatistical_parity_differencereturnednanfor empty
subgroups instead of raising: the rate was a numpy 0/0, and sincenan == 0is
alwaysFalsethe existing zero guard never caught it (and only ever checked the
unprotected group). (#1199)fairness_metrics_fnwas commented out ofpyhealth.metrics; re-enabled and added
to__all__. (#1200)- Removal-based interpretability metrics aliased
original_class_probstoy_probs
and negated negative-class entries in place, flipping the sign on every iteration of
the percentage loop — a sample's score depended on where its percentage sat in the
list. (#1196) - Interpretability
target_class_idxhandling, argument naming, and sample-class
filtering. (#926) - SCRIB: the overall-risk loss squared the chance-ambiguity term, contradicting Eq. 2
and Algorithm 2 of the paper and the already-correct class-specific loss in the same
file; fixed in both the Python and Cython paths, along with afill_maxinference
gap. (#1190) - Covariate-shift conformal prediction fixes. (#1180)
Examples and docs
- Removed the deprecated
code_mapping,dev, andrefresh_cachearguments from
README.rst, example scripts, and leaderboard utilities — the 2.0
MIMIC3Dataset/MIMIC4Datasetno longer accept them. (#935, fixes #535) - Fixed a
SyntaxErrorinexamples/benchmark_perf/loc/minimal_los.py, a missing
__main__guard that hungreadmission_mimic3_fairness.pyunder multiprocessing,
and a staleTransformer(...)call. (#1200) - Reinitialized the documentation tutorials lost in the UIUC purge and re-linked the
Colab notebooks. (#1143, #1146) - Added missing paper citations throughout the codebase. (#1181)
Infrastructure
- CI gate enforcing the PR contribution rules for changes under
pyhealth/
(tools/check_pr_rules.py). (#1176) - Unit tests for
RNNandMultimodalRNN. (#936) - Fixed a pixi warning and the version format for the build backend. (#917)
tools/bump_version.pynow keepspyhealth.__version__in sync with
pyproject.toml, rewrites only the[project]version line, and no longer hangs
when bumping from a non-pre-release version.
Full Changelog: v2.0.1...v2.0.2