Skill Tracer
Skills › Scientific Agent Skills › pyhealth › examples.md

examples.md

155 lines · skills/pyhealth/references/examples.md at 5f2bc03

Open on GitHub

Most marks come from matching words in the file, so treat them as pointers.

1# Recipes for PyHealth 2.0.2
2
3The starter's invented-data CPU path and the public synthetic MIMIC-III
4`set_task -> split -> Transformer -> Trainer` path were executed. Restricted MIMIC-IV,
5full SleepEDF and specialized molecular-model experiments below are illustrative,
6with constructor/schema contracts checked against released source.
7

Recipes for PyHealth 2.0.2

The starter's invented-data CPU path and the public synthetic MIMIC-III set_task -> split -> Transformer -> Trainer path were executed. Restricted MIMIC-IV, full SleepEDF and specialized molecular-model experiments below are illustrative, with constructor/schema contracts checked against released source.

Raw lines 1 to 7
8## 1. A runnable plumbing check
9
10From the skill root:
12```bash
13uv run --no-project --isolated --python 3.12 --with pyhealth==2.0.2 python assets/starter_pipeline.py --demo --epochs 1
14```
16The asset requires an explicit `--demo` or `--root` choice. Demo records are invented.
17For real MIMIC-III, use an authorized local root, e.g. `--root ./data/mimic-iii`;
18optional `--dev` limits patient processing. It checks for both binary classes in
19train/validation/test before AUC evaluation. The public synthetic bucket with `dev=True` (up to 1000 patients) yielded
2020 eligible next-visit samples (18 negative, 2 positive), too few to support three
21partitions with both classes. Use the accuracy-only smoke example in `SKILL.md` to
22check that download; do not interpret its scores clinically.

1. A runnable plumbing check

From the skill root:

uv run --no-project --isolated --python 3.12 --with pyhealth==2.0.2 python assets/starter_pipeline.py --demo --epochs 1

The asset requires an explicit --demo or --root choice. Demo records are invented. For real MIMIC-III, use an authorized local root, e.g. --root ./data/mimic-iii; optional --dev limits patient processing. It checks for both binary classes in train/validation/test before AUC evaluation. The public synthetic bucket with dev=True (up to 1000 patients) yielded 20 eligible next-visit samples (18 negative, 2 positive), too few to support three partitions with both classes. Use the accuracy-only smoke example in SKILL.md to check that download; do not interpret its scores clinically.

Raw lines 8 to 23
Runs code python assets/starter_pipeline.py :13
24## 2. Fit processors only on training patients
26For a modest dataset, gather raw task dictionaries, partition patient IDs, then
27create processed datasets. This example assumes an already configured `base` and
28`task` and was exercised with small synthetic Patient fixtures. For large cohorts,
29implement the same policy with streaming/cache-backed preparation.
31```python
32import random
33from pyhealth.datasets import create_sample_dataset
35raw = [sample for patient in base.iter_patients() for sample in task(patient)]
36ids = sorted({sample["patient_id"] for sample in raw})
37random.Random(42).shuffle(ids)
38n_train, n_val = int(0.6 * len(ids)), int(0.2 * len(ids))
39groups = [set(ids[:n_train]), set(ids[n_train:n_train + n_val]),
40 set(ids[n_train + n_val:])]
41raw_parts = [[s for s in raw if s["patient_id"] in group] for group in groups]
42if any(not part for part in raw_parts):
43 raise ValueError("Need a nonempty cohort in each partition")
44train = create_sample_dataset(raw_parts[0], input_schema=task.input_schema,
45 output_schema=task.output_schema)
46val, test = [create_sample_dataset(
47 part, input_schema=task.input_schema, output_schema=task.output_schema,
48 input_processors=train.input_processors, output_processors=train.output_processors,
49) for part in raw_parts[1:]]
50```
52Check class counts and unknown-code rates; random patient splitting does not
53stratify outcomes or enforce calendar time. Define the target label vocabulary in
54advance, especially for multilabel tasks: silently dropping unseen test labels
55would overstate performance. Keep fitted processors with the checkpoint.

2. Fit processors only on training patients

For a modest dataset, gather raw task dictionaries, partition patient IDs, then create processed datasets. This example assumes an already configured base and task and was exercised with small synthetic Patient fixtures. For large cohorts, implement the same policy with streaming/cache-backed preparation.

import random
from pyhealth.datasets import create_sample_dataset

raw = [sample for patient in base.iter_patients() for sample in task(patient)]
ids = sorted({sample["patient_id"] for sample in raw})
random.Random(42).shuffle(ids)
n_train, n_val = int(0.6 * len(ids)), int(0.2 * len(ids))
groups = [set(ids[:n_train]), set(ids[n_train:n_train + n_val]),
          set(ids[n_train + n_val:])]
raw_parts = [[s for s in raw if s["patient_id"] in group] for group in groups]
if any(not part for part in raw_parts):
    raise ValueError("Need a nonempty cohort in each partition")
train = create_sample_dataset(raw_parts[0], input_schema=task.input_schema,
                              output_schema=task.output_schema)
val, test = [create_sample_dataset(
    part, input_schema=task.input_schema, output_schema=task.output_schema,
    input_processors=train.input_processors, output_processors=train.output_processors,
) for part in raw_parts[1:]]

Check class counts and unknown-code rates; random patient splitting does not stratify outcomes or enforce calendar time. Define the target label vocabulary in advance, especially for multilabel tasks: silently dropping unseen test labels would overstate performance. Keep fitted processors with the checkpoint.

Raw lines 24 to 56
57## 3. MIMIC-IV readmission adaptation
59```python
60from datetime import timedelta
61from pyhealth.datasets import MIMIC4EHRDataset
62from pyhealth.tasks import ReadmissionPredictionMIMIC4
63from pyhealth.models import RETAIN
65base = MIMIC4EHRDataset(
66 root="./data/mimic-iv", # parent of hosp/ and icu/
67 tables=["diagnoses_icd", "procedures_icd", "prescriptions"],
68 cache_dir="./cache/mimic4",
70task = ReadmissionPredictionMIMIC4(window=timedelta(days=30))
71# Apply the patient/processor partition recipe above, then:
72model = RETAIN(dataset=train, embedding_dim=32)
73```
75Use binary metrics with `Trainer(metrics=["pr_auc", "roc_auc"])`. The upstream task
76uses the next recorded admission, excludes the final admission and checks a strict
77less-than threshold. Resolve follow-up completeness and transfers before calling
78this a 30-day post-discharge readmission study. Attention is an inspection aid.

3. MIMIC-IV readmission adaptation

from datetime import timedelta
from pyhealth.datasets import MIMIC4EHRDataset
from pyhealth.tasks import ReadmissionPredictionMIMIC4
from pyhealth.models import RETAIN

base = MIMIC4EHRDataset(
    root="./data/mimic-iv",  # parent of hosp/ and icu/
    tables=["diagnoses_icd", "procedures_icd", "prescriptions"],
    cache_dir="./cache/mimic4",
)
task = ReadmissionPredictionMIMIC4(window=timedelta(days=30))
# Apply the patient/processor partition recipe above, then:
model = RETAIN(dataset=train, embedding_dim=32)

Use binary metrics with Trainer(metrics=["pr_auc", "roc_auc"]). The upstream task uses the next recorded admission, excludes the final admission and checks a strict less-than threshold. Resolve follow-up completeness and transfers before calling this a 30-day post-discharge readmission study. Attention is an inspection aid.

Raw lines 57 to 79
80## 4. Medication recommendation
82```python
83from pyhealth.tasks import DrugRecommendationMIMIC3
84from pyhealth.models import SafeDrug
86task = DrugRecommendationMIMIC3()
87# Use a MIMIC3 base containing diagnoses_icd/procedures_icd/prescriptions;
88# apply the raw-patient partition and training-processor recipe above.
89model = SafeDrug(dataset=train, embedding_dim=32, hidden_dim=32)
90```
92Built-in MIMIC drug tasks map NDC to ATC level 3 and create nested history features;
93current-visit medications are excluded from `drugs_hist`. Verify this on actual
94samples, check mapped label coverage and resource availability. Use explicit
95multilabel metrics such as `pr_auc_samples` and `jaccard_samples`, and report DDI
96behavior separately from predictive accuracy. A safe-sounding model name is not a
97prescribing guarantee. See [models](models.md) for specialized-model caveats.

4. Medication recommendation

from pyhealth.tasks import DrugRecommendationMIMIC3
from pyhealth.models import SafeDrug

task = DrugRecommendationMIMIC3()
# Use a MIMIC3 base containing diagnoses_icd/procedures_icd/prescriptions;
# apply the raw-patient partition and training-processor recipe above.
model = SafeDrug(dataset=train, embedding_dim=32, hidden_dim=32)

Built-in MIMIC drug tasks map NDC to ATC level 3 and create nested history features; current-visit medications are excluded from drugs_hist. Verify this on actual samples, check mapped label coverage and resource availability. Use explicit multilabel metrics such as pr_auc_samples and jaccard_samples, and report DDI behavior separately from predictive accuracy. A safe-sounding model name is not a prescribing guarantee. See models for specialized-model caveats.

Raw lines 80 to 98
99## 5. Length of stay
101```python
102from pyhealth.tasks import LengthOfStayPredictionMIMIC3
103from pyhealth.models import RNN
105task = LengthOfStayPredictionMIMIC3()
106# The base needs prescriptions as well as diagnoses_icd/procedures_icd.
107# Apply the partition/processor recipe, then:
108model = RNN(dataset=train, rnn_type="GRU", embedding_dim=32, hidden_dim=64)
109```
111Use `Trainer(metrics=["accuracy", "f1_macro", "cohen_kappa"])` and a matching
112monitor. The built-in task is whole-visit code-based, ten-class LOS classification;
113filtering features to a declared prediction time is necessary for prospective claims.

5. Length of stay

from pyhealth.tasks import LengthOfStayPredictionMIMIC3
from pyhealth.models import RNN

task = LengthOfStayPredictionMIMIC3()
# The base needs prescriptions as well as diagnoses_icd/procedures_icd.
# Apply the partition/processor recipe, then:
model = RNN(dataset=train, rnn_type="GRU", embedding_dim=32, hidden_dim=64)

Use Trainer(metrics=["accuracy", "f1_macro", "cohen_kappa"]) and a matching monitor. The built-in task is whole-visit code-based, ten-class LOS classification; filtering features to a declared prediction time is necessary for prospective claims.

Raw lines 99 to 114
115## 6. Sleep staging
117```python
118from pyhealth.datasets import SleepEDFDataset
119from pyhealth.tasks import SleepStagingSleepEDF
120from pyhealth.models import SparcNet
122base = SleepEDFDataset(root="./data/sleep-edf", subset="cassette")
123task = SleepStagingSleepEDF(chunk_duration=30.0)
124# Group recordings from one subject together before creating train/val/test.
125# After preparing compatible signal tensors and processors:
126model = SparcNet(dataset=train)
127```
129The root contains `SC-subjects.xls` and `sleep-cassette/` (or `ST-subjects.xls`
130and `sleep-telemetry/`). Initial metadata preparation uses pandas Excel loading
131and can require `xlrd` for the `.xls` workbook. Alternatively provide the correctly
132prepared `sleepedf-cassette-pyhealth.csv`/`sleepedf-telemetry-pyhealth.csv`.
133No `cache_dir=` argument on this dataset wrapper in 2.0.2. Verify person IDs across
134nights; an epoch/recording split is not necessarily a subject split. The built-in
135task retains W/N1/N2/N3/N4/REM as six classes; decide explicitly whether to merge N3/N4.
136Check MNE annotation availability and channel layout before training. Suitable
137multiclass metric names include `accuracy`, `f1_macro`, `cohen_kappa`.

6. Sleep staging

from pyhealth.datasets import SleepEDFDataset
from pyhealth.tasks import SleepStagingSleepEDF
from pyhealth.models import SparcNet

base = SleepEDFDataset(root="./data/sleep-edf", subset="cassette")
task = SleepStagingSleepEDF(chunk_duration=30.0)
# Group recordings from one subject together before creating train/val/test.
# After preparing compatible signal tensors and processors:
model = SparcNet(dataset=train)

The root contains SC-subjects.xls and sleep-cassette/ (or ST-subjects.xls and sleep-telemetry/). Initial metadata preparation uses pandas Excel loading and can require xlrd for the .xls workbook. Alternatively provide the correctly prepared sleepedf-cassette-pyhealth.csv/sleepedf-telemetry-pyhealth.csv. No cache_dir= argument on this dataset wrapper in 2.0.2. Verify person IDs across nights; an epoch/recording split is not necessarily a subject split. The built-in task retains W/N1/N2/N3/N4/REM as six classes; decide explicitly whether to merge N3/N4. Check MNE annotation availability and channel layout before training. Suitable multiclass metric names include accuracy, f1_macro, cohen_kappa.

Raw lines 115 to 138
139## 7. Baselines and checkpoints
141`LogisticRegression(dataset=train)` is a PyHealth embedding-plus-linear-head model.
142Also consider a separately specified fixed-feature baseline when that is the intended
143comparison. Low logistic-model PR-AUC does not prove deeper models cannot help;
144compare with prevalence and inspect data quality/label definitions.
146After training, reuse the same architecture and processor vocabularies:
148```python
149trainer.load_ckpt("./output/experiment/best.ckpt")
150y_true, y_prob, mean_loss = trainer.inference(test_loader)
151```
153The checkpoint path is `output_path/exp_name/best.ckpt` when logging is enabled.
154It contains weights, not a complete preprocessing pipeline. Medical-code-only
155workflows and tested tokenizer examples are in [medical codes](medcode.md).

7. Baselines and checkpoints

LogisticRegression(dataset=train) is a PyHealth embedding-plus-linear-head model. Also consider a separately specified fixed-feature baseline when that is the intended comparison. Low logistic-model PR-AUC does not prove deeper models cannot help; compare with prevalence and inspect data quality/label definitions.

After training, reuse the same architecture and processor vocabularies:

trainer.load_ckpt("./output/experiment/best.ckpt")
y_true, y_prob, mean_loss = trainer.inference(test_loader)

The checkpoint path is output_path/exp_name/best.ckpt when logging is enabled. It contains weights, not a complete preprocessing pipeline. Medical-code-only workflows and tested tokenizer examples are in medical codes.

Raw lines 139 to 155