Add MEDS dataset support (MEDSDataset + typed Parquet scan path)#1179
Draft
AxelNoun wants to merge 6 commits into
Draft
Add MEDS dataset support (MEDSDataset + typed Parquet scan path)#1179AxelNoun wants to merge 6 commits into
AxelNoun wants to merge 6 commits into
Conversation
Route .parquet/.pq files, globs, and directories through a typed _scan_parquet scanner; keep CSV/TSV(.gz) on the existing path. Add a datetime fast-path in load_table that skips the string round-trip and casts to datetime64[ms], preserving NaT for static events.
Declarative YAML wrapper over the shared Parquet scan path, with split_source subset selection (metadata or directory layout), distinct processing caches per subset, and a construction-time Parquet footer schema guard that rejects missing, non-timestamp, or timezone-aware time columns.
Deterministic sharded Parquet fixtures cover nested splits, subset filtering, cache isolation, set_task smoke, and construction-time schema-guard TypeErrors. Demo smoke stays skip-gated behind MEDS_DEMO_ROOT / test-resources/meds_demo (gitignored).
Document MEDSDataset in the API reference and add an end-to-end examples/meds_demo.py against the public PhysioNet MIMIC-IV MEDS demo.
MEDS-native in-hospital mortality task: one sample per completed stay, reconstructed by joining HOSPITAL_ADMISSION/HOSPITAL_DISCHARGE events on hadm_id. Half-open [admit, prediction_time) observation window (full_stay default; first_hours early-warning variant), label from the HOSPITAL_DISCHARGE//DIED discharge code. Discharge and MEDS_DEATH events are excluded from features to prevent label leakage. hadm_id is dataset-specific (not part of the core MEDS schema), so it is exposed via a bundled configs/meds_with_hadm.yaml rather than the default config. Verified on the public MIMIC-IV demo in MEDS: 12 positive / 238 stays (rate 0.0504); set_task sample count 238. - pyhealth/tasks/in_hospital_mortality_meds.py (+ __init__ export) - pyhealth/datasets/configs/meds_with_hadm.yaml - tests/core/test_in_hospital_mortality_meds.py - examples/verify_meds_mortality.py - docs/api/tasks/pyhealth.tasks.InHospitalMortalityMEDS.rst (+ tasks.rst toctree) Co-authored-by: Cursor <cursoragent@cursor.com>
Satisfies ruff F401 on the newly added __init__ line under tools/check_pr_rules scoped lint (same pattern as eegbci). Co-authored-by: Cursor <cursoragent@cursor.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
The Medical Event Data Standard (MEDS) is a minimal, event-based schema for machine learning over EHR data (MEDS Working Group, Medical Event Data Standard (MEDS): Facilitating Machine Learning for Health, ICLR 2024 Workshop on Learning from Time Series For Health, openreview:IsHy2ebjIG). MEDS datasets are distributed as sharded, natively typed Parquet files.
PyHealth currently cannot read Parquet sources:
.parquetpaths and directories fall through the CSV/TSV extension resolver and raiseValueError. Since the MEDS core table maps one-to-one onto PyHealth's canonical event frame (subject_id→patient_id,time→timestamp,code/numeric_valueas attributes), MEDS support is almost purely declarative once Parquet can be scanned.Related to #329 (Integration with MEDS).
Changes
1.
BaseDataset: generic Parquet source support (~90 changed lines)_scan_table: format router —.parquet/.pqfiles, glob patterns, and directories go to the new scanner; everything else falls back to the existing_scan_csv_tsv_gz, unchanged. Non-breaking by construction: all newly routed inputs previously raised._scan_parquet: typed scan (no all-string coercion — Parquet embeds its schema) with the same Dask kwargs as the cached-Parquet read of the CSV path. A directory is scanned recursively, which supports the sharded MEDS layoutdata/<split>/<shard>.parquet. Missing or Parquet-less sources raiseFileNotFoundError.load_table: a fast-path when the configured timestamp column is already datetime-typed — skips the string round-trip, preservesNaT(MEDS static events have nulltime), then applies the usualdatetime64[ms]cast. The list-concatenation and string-parsing branches are untouched.>>>usage example was added to theBaseDatasetdocstring, as required by the PR rules once the class span is modified.2.
MEDSDataset+configs/meds.yamlEHRShotDataset; an optional staticsubject_splitstable mirrors the EHRShotsplitsprecedent.subset="train" | "tuning" | "held_out", resolved viametadata/subject_splits.parquet(with a directory-layout fallback); each subset gets its own processing cache.timecolumn raisesTypeError. The MEDS reference schema is timezone-naivetimestamp[us]; the guard also rejects date-like integer columns (e.g.20240101) that the generic string fallback would otherwise parse silently.3. Tests —
tests/core/test_meds.pyMEDS_DEMO_ROOT(public MIMIC-IV demo data in MEDS, PhysioNet, ODbL v1.0).4. Docs & example
docs/api/datasets/pyhealth.datasets.MEDSDataset.rstexamples/meds_demo.py: end-to-end on the public demo (download instructions included).5.
InHospitalMortalityMEDS(MEDS-native task)hadm_idfromHOSPITAL_ADMISSION//*/HOSPITAL_DISCHARGE//*, label =HOSPITAL_DISCHARGE//DIED, features = ordered codes in half-open[admit, prediction_time)excluding discharge andMEDS_DEATH(anti-leakage). Default windowfull_stay; opt-infirst_hours.hadm_idis not core MEDS, so it stays out ofconfigs/meds.yamland is exposed via bundledconfigs/meds_with_hadm.yaml(absent attributes raise inload_table).examples/verify_meds_mortality.pyprints cohort stats through the real pipeline.docs/api/tasks/pyhealth.tasks.InHospitalMortalityMEDS.rst+ toctree entry indocs/api/tasks.rst.Testing
python -m pytest tests/core/test_meds.py -v: 13 passed (incl. 4 schema-guard subtests) — Windows, Python 3.12.python -m pytest tests/core/test_in_hospital_mortality_meds.py -v: synthetic suite + demo smoke passed (Windows, Python 3.12).master, run via unittest —makeis unavailable on Windows): the only failures are environment-specific and unrelated to this change — temp-dir teardownPermissionErroron Windows (WinError 32), and network-gated GCS synthetic-MIMIC loads whose URLs are mangled by Windows path joining. By construction the CSV path is unchanged: the datetime fast-path can only trigger on typed (non-CSV) sources.mastercheckout on the same machine.patient_idstring,timestampdatetime64[ms]);set_taskexercised with a minimal task.examples/verify_meds_mortality.py --root <demo>): 12 positive / 238 stays (rate 0.0504);set_tasksample count 238.NaT/microsecond behavior of the datetime fast-path, and the silent-parse hazard of date-like integer timestamps (hence the schema guard).How to verify
Notes for review
BaseDatasetParquet path is deliberately generic (reusable by future Parquet-distributed datasets). Happy to split it into its own PR if you prefer smaller diffs.subsetAPI: small and tested, but easy to strip if you want the first cut minimal.test-resources/, following the eICU/MIMIC demo precedent — your call.hadm_idconfig: stay-aware tasks opt intomeds_with_hadm.yaml; the default MEDS config stays core-schema-only so generic MEDS exports withouthadm_idkeep working.Opened as a draft; next updates here: a tutorial notebook.