pyhealth.tasks.generate_ehr#
Tasks that turn a longitudinal EHR dataset into training samples for
unconditional synthetic-EHR generators, plus helpers to flatten generated
output into the long-form dataframe consumed by
pyhealth.metrics.generative.
The classes are flat and independent – one per (model family, dataset). The
extraction is MIMIC-shaped, assuming an admissions event type and a
hadm_id linking codes to an admission, so the dataset is named in the class
and a task for eICU/OMOP/MEDS belongs alongside these rather than below them.
Match the task to the model: each generator family reads its codes in a different shape, and handing a model the wrong shape fails silently rather than loudly.
Task |
Encoding |
Models |
|---|---|---|
|
one multi-hot row per visit |
HALO |
|
per-visit code indices |
GPT2, PromptEHR |
|
one code set per patient |
MedGAN, CorGAN |
Task Classes#
- class pyhealth.tasks.generate_ehr.EHRGenerationMIMIC3(code_mapping=None)[source]#
Bases:
BaseTaskPer-visit ICD-9 code sets from MIMIC-III as multi-hot rows. For HALO.
HALO’s transformer consumes a multi-hot vector per context position, so this hands it exactly that and nothing is repacked on the way in.
Patients with fewer than
min_visitscoded admissions are skipped.Examples
>>> from pyhealth.datasets import MIMIC3Dataset >>> from pyhealth.tasks import EHRGenerationMIMIC3 >>> dataset = MIMIC3Dataset( ... root="/path/to/mimic-iii/1.4", tables=["diagnoses_icd"] ... ) >>> samples = dataset.set_task(EHRGenerationMIMIC3()) >>> samples[0]["visits"].shape # (num_visits, vocab_size) torch.Size([3, 512])
- input_schema: ClassVar[dict[str, str | type]] = {'visits': <class 'pyhealth.processors.nested_multihot_processor.NestedMultiHotProcessor'>}#
- pre_filter(df)#
- Return type:
LazyFrame
- class pyhealth.tasks.generate_ehr.EHRGenerationMIMIC4(code_mapping=None)[source]#
Bases:
BaseTaskPer-visit ICD code sets from MIMIC-IV as multi-hot rows. For HALO.
MIMIC-IV’s diagnosis codes live on
icd_coderather than MIMIC-III’sicd9_code; otherwise identical toEHRGenerationMIMIC3.Examples
>>> from pyhealth.datasets import MIMIC4Dataset >>> from pyhealth.tasks import EHRGenerationMIMIC4 >>> dataset = MIMIC4Dataset( ... ehr_root="/path/to/mimiciv/2.2/", ... ehr_tables=["patients", "admissions", "diagnoses_icd"], ... ) >>> samples = dataset.set_task(EHRGenerationMIMIC4()) >>> samples[0]["visits"].shape # (num_visits, vocab_size) torch.Size([3, 512])
- input_schema: ClassVar[dict[str, str | type]] = {'visits': <class 'pyhealth.processors.nested_multihot_processor.NestedMultiHotProcessor'>}#
- pre_filter(df)#
- Return type:
LazyFrame
- class pyhealth.tasks.generate_ehr.EHRSequenceGenerationMIMIC3(code_mapping=None)[source]#
Bases:
BaseTaskPer-visit ICD-9 code indices from MIMIC-III. For GPT2 and PromptEHR.
Both are token-sequence models: they flatten each visit into a stream of code ids, so indices are what they want. Handing them the multi-hot form means encoding a code set and decoding it straight back.
Examples
>>> from pyhealth.datasets import MIMIC3Dataset >>> from pyhealth.tasks import EHRSequenceGenerationMIMIC3 >>> dataset = MIMIC3Dataset( ... root="/path/to/mimic-iii/1.4", tables=["diagnoses_icd"] ... ) >>> samples = dataset.set_task(EHRSequenceGenerationMIMIC3()) >>> samples[0]["visits"].shape # (num_visits, max_codes_per_visit) torch.Size([3, 12])
- input_schema: ClassVar[dict[str, str | type]] = {'visits': <class 'pyhealth.processors.nested_sequence_processor.NestedSequenceProcessor'>}#
- pre_filter(df)#
- Return type:
LazyFrame
- class pyhealth.tasks.generate_ehr.EHRSequenceGenerationMIMIC4(code_mapping=None)[source]#
Bases:
BaseTaskPer-visit ICD code indices from MIMIC-IV. For GPT2 and PromptEHR.
Examples
>>> from pyhealth.datasets import MIMIC4Dataset >>> from pyhealth.tasks import EHRSequenceGenerationMIMIC4 >>> dataset = MIMIC4Dataset( ... ehr_root="/path/to/mimiciv/2.2/", ... ehr_tables=["patients", "admissions", "diagnoses_icd"], ... ) >>> samples = dataset.set_task(EHRSequenceGenerationMIMIC4()) >>> samples[0]["visits"].shape # (num_visits, max_codes_per_visit) torch.Size([3, 12])
- input_schema: ClassVar[dict[str, str | type]] = {'visits': <class 'pyhealth.processors.nested_sequence_processor.NestedSequenceProcessor'>}#
- pre_filter(df)#
- Return type:
LazyFrame
- class pyhealth.tasks.generate_ehr.EHRCodeSetGenerationMIMIC3(code_mapping=None)[source]#
Bases:
BaseTaskOne pooled ICD-9 code set per MIMIC-III patient. For MedGAN and CorGAN.
Bag-of-codes generators emit a single aggregate vector per patient, so the visit axis is collapsed here rather than inside the model.
min_visitsstill counts real admissions, before the codes are pooled.Note
With the visit axis gone, the next-visit utility metric in
pyhealth.metrics.generativeis not meaningful for these models; see this module’s header.Examples
>>> from pyhealth.datasets import MIMIC3Dataset >>> from pyhealth.tasks import EHRCodeSetGenerationMIMIC3 >>> dataset = MIMIC3Dataset( ... root="/path/to/mimic-iii/1.4", tables=["diagnoses_icd"] ... ) >>> samples = dataset.set_task(EHRCodeSetGenerationMIMIC3()) >>> samples[0]["visits"].shape # (vocab_size,) torch.Size([512])
- input_schema: ClassVar[dict[str, str | type]] = {'visits': <class 'pyhealth.processors.multi_hot_processor.MultiHotProcessor'>}#
- pre_filter(df)#
- Return type:
LazyFrame
- class pyhealth.tasks.generate_ehr.EHRCodeSetGenerationMIMIC4(code_mapping=None)[source]#
Bases:
BaseTaskOne pooled ICD code set per MIMIC-IV patient. For MedGAN and CorGAN.
Examples
>>> from pyhealth.datasets import MIMIC4Dataset >>> from pyhealth.tasks import EHRCodeSetGenerationMIMIC4 >>> dataset = MIMIC4Dataset( ... ehr_root="/path/to/mimiciv/2.2/", ... ehr_tables=["patients", "admissions", "diagnoses_icd"], ... ) >>> samples = dataset.set_task(EHRCodeSetGenerationMIMIC4()) >>> samples[0]["visits"].shape # (vocab_size,) torch.Size([512])
- input_schema: ClassVar[dict[str, str | type]] = {'visits': <class 'pyhealth.processors.multi_hot_processor.MultiHotProcessor'>}#
- pre_filter(df)#
- Return type:
LazyFrame
Helper Functions#
- pyhealth.tasks.generate_ehr.decode_dataset(sample_dataset, feature_key='visits')[source]#
Decode a processed multi-hot
SampleDatasetback into code records.Inverts the
NestedMultiHotProcessorencoding using its vocabulary (skipping<pad>/<unk>), yielding one{"visits": [[code_str, ...], ...]}record per sample. Use this to build the real train/test frames thatevaluate_synthetic_ehrcompares against.Codes come back in vocabulary order, not the order they were charted in, and repeats collapse – the multi-hot form records presence, not sequence or count within a visit.
- Parameters:
sample_dataset – A
SampleDataset(or a split of one) produced byEHRGenerationMIMIC3/EHRGenerationMIMIC4.feature_key (
str) – Input feature key holding the nested code sequence. Default"visits".
- Return type:
- Returns:
List of
{"visits": [[code_str, ...], ...]}records.- Raises:
TypeError – If
feature_keyis not backed by aNestedMultiHotProcessor.
Examples
>>> from pyhealth.tasks.generate_ehr import decode_dataset >>> records = decode_dataset(samples) >>> records[0]["visits"][0] ['4019', '25000']
- pyhealth.tasks.generate_ehr.to_evaluation_dataframe(records, label_fn=None, subject_col='id', visit_col='time', code_col='visit_codes', label_col='labels')[source]#
Flatten EHR-generation records into the long-form evaluation dataframe.
Produces the one-row-per-
(patient, visit, code)table consumed bypyhealth.metrics.generative.evaluate_synthetic_ehr()(and theutils.py/privacy.py/utility.pyfunctions beneath it).Subjects are numbered sequentially (0, 1, 2, …) in
subject_col; any"patient_id"on the records is ignored, since synthetic patients do not correspond to real ones.- Parameters:
records – Iterable of
{"visits": [[code, ...], ...]}dicts. Both the generation tasks’ output and a generator’sgenerate()output have this shape.label_fn (
Optional[Callable[dict,int]]) – Optional callable mapping a record to a binary patient label (0/1) used by the utility metrics. Defaults to all-zeros.subject_col (
str) – Output patient-id column. Default"id".visit_col (
str) – Output visit-index column. Default"time".code_col (
str) – Output single-code column. Default"visit_codes".label_col (
str) – Output binary-label column. Default"labels".
- Returns:
pandas.DataFramewith columns[subject_col, visit_col, code_col, label_col].
Examples
>>> from pyhealth.tasks.generate_ehr import to_evaluation_dataframe >>> records = [{"visits": [["4019", "25000"], ["4019"]]}] >>> to_evaluation_dataframe(records) id time visit_codes labels 0 0 0 4019 0 1 0 0 25000 0 2 0 1 4019 0