diff --git a/README.rst b/README.rst index c3f3e6355..3940f774d 100644 --- a/README.rst +++ b/README.rst @@ -354,23 +354,23 @@ Module 5: We provide the following tutorials to help users get started with our pyhealth. Please bear with us as we update the documentation on how to use PyHealth 2.0. -`Tutorial 0: Introduction to pyhealth.data `_ `[Video] `__ +`Tutorial 0: Introduction to pyhealth.data `_ `[Video] `__ -`Tutorial 1: Introduction to pyhealth.datasets `_ `[Video (PyHealth 1.16)] `__ +`Tutorial 1: Introduction to pyhealth.datasets `_ `[Video (PyHealth 1.16)] `__ -`Tutorial 2: Introduction to pyhealth.tasks `_ `[Video (PyHealth 1.16)] `__ +`Tutorial 2: Introduction to pyhealth.tasks `_ `[Video (PyHealth 1.16)] `__ -`Tutorial 3: Introduction to pyhealth.models `_ `[Video] `__ +`Tutorial 3: Introduction to pyhealth.models `_ `[Video] `__ -`Tutorial 4: Introduction to pyhealth.trainer `_ `[Video] `__ +`Tutorial 4: Introduction to pyhealth.trainer `_ `[Video] `__ -`Tutorial 5: Introduction to pyhealth.metrics `_ `[Video] `__ +`Tutorial 5: Introduction to pyhealth.metrics `_ `[Video] `__ -`Tutorial 6: Introduction to pyhealth.tokenizer `_ `[Video] `__ +`Tutorial 6: Introduction to pyhealth.tokenizer `_ `[Video] `__ -`Tutorial 7: Introduction to pyhealth.medcode `_ `[Video] `__ +`Tutorial 7: Introduction to pyhealth.medcode `_ `[Video] `__ The following tutorials will help users build their own task pipelines. diff --git a/chat-assistant/corpus/pyhealth-code.txt b/chat-assistant/corpus/pyhealth-code.txt index 5af6889c0..0ecef087d 100644 --- a/chat-assistant/corpus/pyhealth-code.txt +++ b/chat-assistant/corpus/pyhealth-code.txt @@ -26786,7 +26786,7 @@ Here is the code content for tutorial_5_pyhealth_metrics.py: Automatically generated by Colaboratory. Original file is located at - https://colab.research.google.com/drive/1Mrs77EJ92HwMgDaElJ_CBXbi4iABZBeo + https://colab.research.google.com/drive/1bO0h5BR62_kQ7zFOgzQmt5vb8jqJ0rV-?usp=drive_link ### **Preparation** - install pyhealth alpha version @@ -27611,7 +27611,7 @@ Here is the code content for tutorial_0_pyhealth_data.py: Automatically generated by Colaboratory. Original file is located at - https://colab.research.google.com/drive/1y9PawgSbyMbSSMw1dpfwtooH7qzOEYdN + https://colab.research.google.com/drive/17nOzjIjKiAbC8bsntZ3h9xy2Vq4bKpuv """ !pip install pyhealth @@ -28478,7 +28478,7 @@ test_loader = get_dataloader(test_ds, batch_size=64, shuffle=False) """### **Step 2: Select a ML model** - In this tutorial, we use Transformer as the example. -- please check the [Tutorial 2](https://colab.research.google.com/drive/1LcXZlu7ZUuqepf269X3FhXuhHeRvaJX5?usp=sharing) for more instructions on how to initialize a model. +- please check the [Tutorial 2](https://colab.research.google.com/drive/1cUTSfFL1wLUXDBtJGTAWntolvcmxrDGo?usp=drive_link) for more instructions on how to initialize a model. """ from pyhealth.models import Transformer @@ -28532,7 +28532,7 @@ Here is the code content for tutorial_6_pyhealth_tokenizer.py: Automatically generated by Colaboratory. Original file is located at - https://colab.research.google.com/drive/1bDOb0A5g0umBjtz8NIp4wqye7taJ03D0 + https://colab.research.google.com/drive/1jhJ11MLUafhflQAz8HSrWiOEYlIhhvc_ ### **Preparation** - install pyhealth alpha version @@ -29093,7 +29093,7 @@ Here is the code content for tutorial_7_pyhealth_medcode.py: Automatically generated by Colaboratory. Original file is located at - https://colab.research.google.com/drive/1xrp_ACM2_Hg5Wxzj0SKKKgZfMY0WwEj3 + https://colab.research.google.com/drive/1Tw1AUS53fotH1EYr4Abp7qYN3zDBeUbC?usp=drive_link ### **Preparation** - install pyhealth alpha version @@ -29625,7 +29625,7 @@ Here is the code content for tutorial_3_pyhealth_models.py: Automatically generated by Colaboratory. Original file is located at - https://colab.research.google.com/drive/1LcXZlu7ZUuqepf269X3FhXuhHeRvaJX5 + https://colab.research.google.com/drive/1cUTSfFL1wLUXDBtJGTAWntolvcmxrDGo?usp=drive_link ### **Preparation** - install pyhealth alpha version @@ -30421,7 +30421,7 @@ Here is the code content for tutorial_4_pyhealth_trainer.py: Automatically generated by Colaboratory. Original file is located at - https://colab.research.google.com/drive/1L1Nz76cRNB7wTp5Pz_4Vp4N2eRZ9R6xl + https://colab.research.google.com/drive/1up_SL0BxxHPO9pmjKQ98w1GbpiB7LySp?usp=drive_link ### **Preparation** - install pyhealth alpha version @@ -30457,7 +30457,7 @@ To initialize a trainer instance, the following environments should be specified - `load_best_model_at_last`: whether to load the best model during the last iteration. ### **Step 1 & 2 & 3: Prepare datasets, task, and model** -- Example: We use **MIMIC-III dataset** and **RETAIN** model for **readmission prediction** task. Refer to [Tutorial 1](https://colab.research.google.com/drive/18kbzEQAj1FMs_J9rTGX8eCoxnWdx4Ltn?usp=sharing), [Tutorial 2](https://colab.research.google.com/drive/1r7MYQR_5yCJGpK_9I9-A10HmpupZuIN-?usp=sharing), and [Tutorial 3](https://colab.research.google.com/drive/1LcXZlu7ZUuqepf269X3FhXuhHeRvaJX5?usp=sharing). +- Example: We use **MIMIC-III dataset** and **RETAIN** model for **readmission prediction** task. Refer to [Tutorial 1](https://colab.research.google.com/drive/18kbzEQAj1FMs_J9rTGX8eCoxnWdx4Ltn?usp=sharing), [Tutorial 2](https://colab.research.google.com/drive/1r7MYQR_5yCJGpK_9I9-A10HmpupZuIN-?usp=sharing), and [Tutorial 3](https://colab.research.google.com/drive/1cUTSfFL1wLUXDBtJGTAWntolvcmxrDGo?usp=drive_link). """ # load dataset diff --git a/chat-assistant/corpus/pyhealth-text.txt b/chat-assistant/corpus/pyhealth-text.txt index 5d0d59992..705fed027 100644 --- a/chat-assistant/corpus/pyhealth-text.txt +++ b/chat-assistant/corpus/pyhealth-text.txt @@ -326,23 +326,23 @@ Module 5: We provide the following tutorials to help users get started with our pyhealth. -`Tutorial 0: Introduction to pyhealth.data `_ `[Video] `__ +`Tutorial 0: Introduction to pyhealth.data `_ `[Video] `__ `Tutorial 1: Introduction to pyhealth.datasets `_ `[Video] `__ `Tutorial 2: Introduction to pyhealth.tasks `_ `[Video] `__ -`Tutorial 3: Introduction to pyhealth.models `_ `[Video] `__ +`Tutorial 3: Introduction to pyhealth.models `_ `[Video] `__ -`Tutorial 4: Introduction to pyhealth.trainer `_ `[Video] `__ +`Tutorial 4: Introduction to pyhealth.trainer `_ `[Video] `__ -`Tutorial 5: Introduction to pyhealth.metrics `_ `[Video] `__ +`Tutorial 5: Introduction to pyhealth.metrics `_ `[Video] `__ -`Tutorial 6: Introduction to pyhealth.tokenizer `_ `[Video] `__ +`Tutorial 6: Introduction to pyhealth.tokenizer `_ `[Video] `__ -`Tutorial 7: Introduction to pyhealth.medcode `_ `[Video] `__ +`Tutorial 7: Introduction to pyhealth.medcode `_ `[Video] `__ The following tutorials will help users build their own task pipelines. @@ -1206,21 +1206,21 @@ Tutorials We provide the following tutorials to help users get started with our pyhealth. -`Tutorial 0: Introduction to pyhealth.data `_ `[Video] `_ +`Tutorial 0: Introduction to pyhealth.data `_ `[Video] `_ `Tutorial 1: Introduction to pyhealth.datasets `_ `[Video] `_ `Tutorial 2: Introduction to pyhealth.tasks `_ `[Video] `_ -`Tutorial 3: Introduction to pyhealth.models `_ `[Video] `_ +`Tutorial 3: Introduction to pyhealth.models `_ `[Video] `_ -`Tutorial 4: Introduction to pyhealth.trainer `_ `[Video] `_ +`Tutorial 4: Introduction to pyhealth.trainer `_ `[Video] `_ -`Tutorial 5: Introduction to pyhealth.metrics `_ `[Video] `_ +`Tutorial 5: Introduction to pyhealth.metrics `_ `[Video] `_ -`Tutorial 6: Introduction to pyhealth.tokenizer `_ `[Video] `_ +`Tutorial 6: Introduction to pyhealth.tokenizer `_ `[Video] `_ -`Tutorial 7: Introduction to pyhealth.medcode `_ `[Video] `_ +`Tutorial 7: Introduction to pyhealth.medcode `_ `[Video] `_ The following tutorials will help users build their own task pipelines. `[Video] `_ diff --git a/chat-assistant/corpus/pyhealth.txt b/chat-assistant/corpus/pyhealth.txt index 10cd5456e..309f791de 100644 --- a/chat-assistant/corpus/pyhealth.txt +++ b/chat-assistant/corpus/pyhealth.txt @@ -326,23 +326,23 @@ Module 5: We provide the following tutorials to help users get started with our pyhealth. -`Tutorial 0: Introduction to pyhealth.data `_ `[Video] `__ +`Tutorial 0: Introduction to pyhealth.data `_ `[Video] `__ `Tutorial 1: Introduction to pyhealth.datasets `_ `[Video] `__ `Tutorial 2: Introduction to pyhealth.tasks `_ `[Video] `__ -`Tutorial 3: Introduction to pyhealth.models `_ `[Video] `__ +`Tutorial 3: Introduction to pyhealth.models `_ `[Video] `__ -`Tutorial 4: Introduction to pyhealth.trainer `_ `[Video] `__ +`Tutorial 4: Introduction to pyhealth.trainer `_ `[Video] `__ -`Tutorial 5: Introduction to pyhealth.metrics `_ `[Video] `__ +`Tutorial 5: Introduction to pyhealth.metrics `_ `[Video] `__ -`Tutorial 6: Introduction to pyhealth.tokenizer `_ `[Video] `__ +`Tutorial 6: Introduction to pyhealth.tokenizer `_ `[Video] `__ -`Tutorial 7: Introduction to pyhealth.medcode `_ `[Video] `__ +`Tutorial 7: Introduction to pyhealth.medcode `_ `[Video] `__ The following tutorials will help users build their own task pipelines. @@ -1206,21 +1206,21 @@ Tutorials We provide the following tutorials to help users get started with our pyhealth. -`Tutorial 0: Introduction to pyhealth.data `_ `[Video] `_ +`Tutorial 0: Introduction to pyhealth.data `_ `[Video] `_ `Tutorial 1: Introduction to pyhealth.datasets `_ `[Video] `_ `Tutorial 2: Introduction to pyhealth.tasks `_ `[Video] `_ -`Tutorial 3: Introduction to pyhealth.models `_ `[Video] `_ +`Tutorial 3: Introduction to pyhealth.models `_ `[Video] `_ -`Tutorial 4: Introduction to pyhealth.trainer `_ `[Video] `_ +`Tutorial 4: Introduction to pyhealth.trainer `_ `[Video] `_ -`Tutorial 5: Introduction to pyhealth.metrics `_ `[Video] `_ +`Tutorial 5: Introduction to pyhealth.metrics `_ `[Video] `_ -`Tutorial 6: Introduction to pyhealth.tokenizer `_ `[Video] `_ +`Tutorial 6: Introduction to pyhealth.tokenizer `_ `[Video] `_ -`Tutorial 7: Introduction to pyhealth.medcode `_ `[Video] `_ +`Tutorial 7: Introduction to pyhealth.medcode `_ `[Video] `_ The following tutorials will help users build their own task pipelines. `[Video] `_ @@ -28027,7 +28027,7 @@ Here is the code content for tutorial_5_pyhealth_metrics.py: Automatically generated by Colaboratory. Original file is located at - https://colab.research.google.com/drive/1Mrs77EJ92HwMgDaElJ_CBXbi4iABZBeo + https://colab.research.google.com/drive/1bO0h5BR62_kQ7zFOgzQmt5vb8jqJ0rV-?usp=drive_link ### **Preparation** - install pyhealth alpha version @@ -28852,7 +28852,7 @@ Here is the code content for tutorial_0_pyhealth_data.py: Automatically generated by Colaboratory. Original file is located at - https://colab.research.google.com/drive/1y9PawgSbyMbSSMw1dpfwtooH7qzOEYdN + https://colab.research.google.com/drive/17nOzjIjKiAbC8bsntZ3h9xy2Vq4bKpuv """ !pip install pyhealth @@ -29719,7 +29719,7 @@ test_loader = get_dataloader(test_ds, batch_size=64, shuffle=False) """### **Step 2: Select a ML model** - In this tutorial, we use Transformer as the example. -- please check the [Tutorial 2](https://colab.research.google.com/drive/1LcXZlu7ZUuqepf269X3FhXuhHeRvaJX5?usp=sharing) for more instructions on how to initialize a model. +- please check the [Tutorial 2](https://colab.research.google.com/drive/1cUTSfFL1wLUXDBtJGTAWntolvcmxrDGo?usp=drive_link) for more instructions on how to initialize a model. """ from pyhealth.models import Transformer @@ -29773,7 +29773,7 @@ Here is the code content for tutorial_6_pyhealth_tokenizer.py: Automatically generated by Colaboratory. Original file is located at - https://colab.research.google.com/drive/1bDOb0A5g0umBjtz8NIp4wqye7taJ03D0 + https://colab.research.google.com/drive/1jhJ11MLUafhflQAz8HSrWiOEYlIhhvc_ ### **Preparation** - install pyhealth alpha version @@ -30334,7 +30334,7 @@ Here is the code content for tutorial_7_pyhealth_medcode.py: Automatically generated by Colaboratory. Original file is located at - https://colab.research.google.com/drive/1xrp_ACM2_Hg5Wxzj0SKKKgZfMY0WwEj3 + https://colab.research.google.com/drive/1Tw1AUS53fotH1EYr4Abp7qYN3zDBeUbC?usp=drive_link ### **Preparation** - install pyhealth alpha version @@ -30866,7 +30866,7 @@ Here is the code content for tutorial_3_pyhealth_models.py: Automatically generated by Colaboratory. Original file is located at - https://colab.research.google.com/drive/1LcXZlu7ZUuqepf269X3FhXuhHeRvaJX5 + https://colab.research.google.com/drive/1cUTSfFL1wLUXDBtJGTAWntolvcmxrDGo?usp=drive_link ### **Preparation** - install pyhealth alpha version @@ -31662,7 +31662,7 @@ Here is the code content for tutorial_4_pyhealth_trainer.py: Automatically generated by Colaboratory. Original file is located at - https://colab.research.google.com/drive/1L1Nz76cRNB7wTp5Pz_4Vp4N2eRZ9R6xl + https://colab.research.google.com/drive/1up_SL0BxxHPO9pmjKQ98w1GbpiB7LySp?usp=drive_link ### **Preparation** - install pyhealth alpha version @@ -31698,7 +31698,7 @@ To initialize a trainer instance, the following environments should be specified - `load_best_model_at_last`: whether to load the best model during the last iteration. ### **Step 1 & 2 & 3: Prepare datasets, task, and model** -- Example: We use **MIMIC-III dataset** and **RETAIN** model for **readmission prediction** task. Refer to [Tutorial 1](https://colab.research.google.com/drive/18kbzEQAj1FMs_J9rTGX8eCoxnWdx4Ltn?usp=sharing), [Tutorial 2](https://colab.research.google.com/drive/1r7MYQR_5yCJGpK_9I9-A10HmpupZuIN-?usp=sharing), and [Tutorial 3](https://colab.research.google.com/drive/1LcXZlu7ZUuqepf269X3FhXuhHeRvaJX5?usp=sharing). +- Example: We use **MIMIC-III dataset** and **RETAIN** model for **readmission prediction** task. Refer to [Tutorial 1](https://colab.research.google.com/drive/18kbzEQAj1FMs_J9rTGX8eCoxnWdx4Ltn?usp=sharing), [Tutorial 2](https://colab.research.google.com/drive/1r7MYQR_5yCJGpK_9I9-A10HmpupZuIN-?usp=sharing), and [Tutorial 3](https://colab.research.google.com/drive/1cUTSfFL1wLUXDBtJGTAWntolvcmxrDGo?usp=drive_link). """ # load dataset diff --git a/docs/_static/external_links.js b/docs/_static/external_links.js new file mode 100644 index 000000000..1cc5cb605 --- /dev/null +++ b/docs/_static/external_links.js @@ -0,0 +1,9 @@ +// Open every external link (http/https, different host) in a new tab. +document.addEventListener("DOMContentLoaded", () => { + for (const a of document.querySelectorAll('a[href^="http"]')) { + if (!a.href.includes(window.location.host)) { + a.target = "_blank"; + a.rel = "noopener noreferrer"; + } + } +}); diff --git a/docs/api/data.rst b/docs/api/data.rst index c6e940a68..411d4857a 100644 --- a/docs/api/data.rst +++ b/docs/api/data.rst @@ -8,7 +8,7 @@ Getting Started New to PyHealth's data structures? Start here: -- **Tutorial**: `Introduction to pyhealth.data `_ | `Video `_ +- **Tutorial**: `Introduction to pyhealth.data `_ | `Video `_ This tutorial introduces the core data structures in PyHealth: diff --git a/docs/api/datasets.rst b/docs/api/datasets.rst index 8d9a59d21..1875698ae 100644 --- a/docs/api/datasets.rst +++ b/docs/api/datasets.rst @@ -6,7 +6,7 @@ Getting Started New to PyHealth datasets? Start here: -- **Tutorial**: `Introduction to pyhealth.datasets `_ | `Video (PyHealth 1.6) `_ +- **Tutorial**: `Introduction to pyhealth.datasets `_ | `Video (PyHealth 1.6) `_ This tutorial covers: diff --git a/docs/api/tasks.rst b/docs/api/tasks.rst index 23a4e06e5..69e5aa592 100644 --- a/docs/api/tasks.rst +++ b/docs/api/tasks.rst @@ -18,7 +18,7 @@ Getting Started New to PyHealth tasks? Start here: -- **Tutorial**: `Introduction to pyhealth.tasks `_ - Learn the basics of defining and using tasks +- **Tutorial**: `Introduction to pyhealth.tasks `_ - Learn the basics of defining and using tasks - **Code Examples**: Browse all examples online at https://github.com/sunlabuiuc/PyHealth/tree/master/examples - **Pipeline Examples**: Check out our :doc:`../tutorials` page for complete end-to-end examples including: diff --git a/docs/conf.py b/docs/conf.py index 1591cdd47..72d742b7b 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -190,6 +190,7 @@ } html_css_files = ["css/override.css", "css/sphinx_gallery.css"] +html_js_files = ["external_links.js"] html_show_sphinx = False # -- Options for HTMLHelp output --------------------------------------------- diff --git a/docs/tutorials.rst b/docs/tutorials.rst index fcdab84ea..9193c86c0 100644 --- a/docs/tutorials.rst +++ b/docs/tutorials.rst @@ -4,21 +4,21 @@ Tutorials We provide the following tutorials to help users get started with our pyhealth. Please bear with us as we update the documentation on how to use pyhealth 2.0. -`Tutorial 0: Introduction to pyhealth.data `_ `[Video] `_ +`Tutorial 0: Introduction to pyhealth.data `_ `[Video] `_ -`Tutorial 1: Introduction to pyhealth.datasets `_ `[Video (PyHealth 1.16)] `_ +`Tutorial 1: Introduction to pyhealth.datasets `_ `[Video (PyHealth 1.16)] `_ -`Tutorial 2: Introduction to pyhealth.tasks `_ `[Video (PyHealth 1.16)] `_ +`Tutorial 2: Introduction to pyhealth.tasks `_ `[Video (PyHealth 1.16)] `_ -`Tutorial 3: Introduction to pyhealth.models `_ `[Video] `_ +`Tutorial 3: Introduction to pyhealth.models `_ `[Video] `_ -`Tutorial 4: Introduction to pyhealth.trainer `_ `[Video] `_ +`Tutorial 4: Introduction to pyhealth.trainer `_ `[Video] `_ -`Tutorial 5: Introduction to pyhealth.metrics `_ `[Video] `_ +`Tutorial 5: Introduction to pyhealth.metrics `_ `[Video] `_ -`Tutorial 6: Introduction to pyhealth.tokenizer `_ `[Video] `_ +`Tutorial 6: Introduction to pyhealth.tokenizer `_ `[Video] `_ -`Tutorial 7: Introduction to pyhealth.medcode `_ `[Video] `_ +`Tutorial 7: Introduction to pyhealth.medcode `_ `[Video] `_ Data Access Guide diff --git a/examples/tutorial_stagenet_comprehensive.ipynb b/examples/tutorial_stagenet_comprehensive.ipynb index 7e1a9a3fd..de7956e27 100644 --- a/examples/tutorial_stagenet_comprehensive.ipynb +++ b/examples/tutorial_stagenet_comprehensive.ipynb @@ -35,7 +35,7 @@ "\n", "The result is a single dataframe where each row represents one patient and their features.\n", "\n", - "For more details on PyHealth datasets, see [this resource](https://colab.research.google.com/drive/1voSx7wEfzXfEf2sIfW6b-8p1KqMyuWxK#scrollTo=NSrb2PGFqUgS).\n", + "For more details on PyHealth datasets, see [this resource](https://colab.research.google.com/drive/1vI_oljc7rU5ocsC26ITM7HUgD5SGZkFE#scrollTo=NSrb2PGFqUgS).\n", "```" ] }, @@ -573,7 +573,7 @@ "\n", "Here, each feature will also need have its own corresponding time intervals. As defined by the StageNet paper, each time interval is defined as the difference in time between the current visit and the previous visit. \n", "\n", - "To define a task, specify the `__call__` method, input schema, and output schema. For a detailed explanation, see [this tutorial](https://colab.research.google.com/drive/1kKKBVS_GclHoYTbnOtjyYnSee79hsyT?usp=sharing).\n", + "To define a task, specify the `__call__` method, input schema, and output schema. For a detailed explanation, see [this tutorial](https://colab.research.google.com/drive/1QB0acnGb-wOuK53UNSgHxjCW74QeYjUl?usp=sharing).\n", "\n", "### Helper Functions\n", "\n", diff --git a/examples/tutorials/orig_tutorial_pyhealth_datasets.ipynb b/examples/tutorials/orig_tutorial_pyhealth_datasets.ipynb new file mode 100644 index 000000000..635d9fa80 --- /dev/null +++ b/examples/tutorials/orig_tutorial_pyhealth_datasets.ipynb @@ -0,0 +1,1613 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "source": [ + "# **Table of Contents**\n", + "In this tutorial, we will go over the following:\n", + "\n", + "0. **PyHealth datasets are not tasks.**\n", + "1. **Using an existing dataset (MIMIC3) to explore data efficiently**\n", + "2. **How data (events) is pre-loaded in PyHealth**\n", + "3. **Deep dive on how to implement and contribute your own PyHealth dataset**\n", + "\n", + "\n" + ], + "metadata": { + "id": "oVqm_kYbpJDn" + } + }, + { + "cell_type": "markdown", + "source": [ + "## **PyHealth datasets are not the same thing as tasks**\n", + "Before we start, we need to conceptualize how pyhealth.datasets work within the wider framework. Specifically, there's commonly a **misconception where people try to contribute dataset code that are more suitable for [pyhealth.tasks](https://github.com/sunlabuiuc/PyHealth/blob/master/pyhealth/tasks/base_task.py)**. While this might be functionally equivalent in some cases, it's not always true.\n", + "\n", + "![Image description](https://drive.google.com/uc?export=view&id=1hHJcavXqisH9JEMqEVtE4TqEg_E489l5)\n", + "\n", + "For instance, in PyHealth and in general, MIMIC3/4 will often have a variety of tasks that are based on the same dataset (i.e mortality prediction, readmission prediction, medical coding, etc.)\n", + "\n", + "While other datasets were originally intended to serve one purpose like SHHS serving the purpose of sleep staging classification, **many datasets serve as more of a pool of data than an annotated benchmark.** The pyhealth.datasets serves to make preprocessing this pool of data easier and more reproducible for the wider-community.\n", + "\n", + "\n", + "**For contributors**: This means that any dataset contribution has to be something that isn't already implemented in PyHealth (i.e MIMIC3/MIMIC4, etc.). So, if you're trying to do synthetic data generation with MIMIC3, please see the pyhealth.tasks [tutorial](https://colab.research.google.com/drive/1QB0acnGb-wOuK53UNSgHxjCW74QeYjUl?usp=sharing) instead of implementing your own synthetic data generation dataset." + ], + "metadata": { + "id": "YuvhioBXxWZC" + } + }, + { + "cell_type": "markdown", + "source": [ + "### Installation Procedure: To be changed to a pip install when a stable version is released." + ], + "metadata": { + "id": "0UEVz4s0K-nx" + } + }, + { + "cell_type": "code", + "source": [ + "!pip install pyhealth" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "-hT1DVoMIPkz", + "outputId": "5a069b25-d9b1-48b7-fd95-1c12a2779fba" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Requirement already satisfied: pyhealth in /usr/local/lib/python3.12/dist-packages (2.0.0)\n", + "Requirement already satisfied: accelerate in /usr/local/lib/python3.12/dist-packages (from pyhealth) (1.12.0)\n", + "Requirement already satisfied: dask~=2025.11.0 in /usr/local/lib/python3.12/dist-packages (from dask[complete]~=2025.11.0->pyhealth) (2025.11.0)\n", + "Requirement already satisfied: einops>=0.8.0 in /usr/local/lib/python3.12/dist-packages (from pyhealth) (0.8.2)\n", + "Requirement already satisfied: linear-attention-transformer>=0.19.1 in /usr/local/lib/python3.12/dist-packages (from pyhealth) (0.19.1)\n", + "Requirement already satisfied: litdata~=0.2.59 in /usr/local/lib/python3.12/dist-packages (from pyhealth) (0.2.61)\n", + "Requirement already satisfied: mne~=1.10.0 in /usr/local/lib/python3.12/dist-packages (from pyhealth) (1.10.2)\n", + "Requirement already satisfied: more-itertools~=10.8.0 in /usr/local/lib/python3.12/dist-packages (from pyhealth) (10.8.0)\n", + "Requirement already satisfied: narwhals~=2.13.0 in /usr/local/lib/python3.12/dist-packages (from pyhealth) (2.13.0)\n", + "Requirement already satisfied: networkx in /usr/local/lib/python3.12/dist-packages (from pyhealth) (3.6.1)\n", + "Requirement already satisfied: numpy~=2.2.0 in /usr/local/lib/python3.12/dist-packages (from pyhealth) (2.2.6)\n", + "Requirement already satisfied: ogb>=1.3.5 in /usr/local/lib/python3.12/dist-packages (from pyhealth) (1.3.6)\n", + "Requirement already satisfied: pandas~=2.3.1 in /usr/local/lib/python3.12/dist-packages (from pyhealth) (2.3.3)\n", + "Requirement already satisfied: peft in /usr/local/lib/python3.12/dist-packages (from pyhealth) (0.18.1)\n", + "Requirement already satisfied: polars~=1.35.2 in /usr/local/lib/python3.12/dist-packages (from pyhealth) (1.35.2)\n", + "Requirement already satisfied: pyarrow~=22.0.0 in /usr/local/lib/python3.12/dist-packages (from pyhealth) (22.0.0)\n", + "Requirement already satisfied: pydantic~=2.11.7 in /usr/local/lib/python3.12/dist-packages (from pyhealth) (2.11.10)\n", + "Requirement already satisfied: rdkit in /usr/local/lib/python3.12/dist-packages (from pyhealth) (2025.9.5)\n", + "Requirement already satisfied: scikit-learn~=1.7.0 in /usr/local/lib/python3.12/dist-packages (from pyhealth) (1.7.2)\n", + "Requirement already satisfied: torchvision in /usr/local/lib/python3.12/dist-packages (from pyhealth) (0.22.1)\n", + "Requirement already satisfied: torch~=2.7.1 in /usr/local/lib/python3.12/dist-packages (from pyhealth) (2.7.1)\n", + "Requirement already satisfied: tqdm in /usr/local/lib/python3.12/dist-packages (from pyhealth) (4.67.3)\n", + "Requirement already satisfied: transformers~=4.53.2 in /usr/local/lib/python3.12/dist-packages (from pyhealth) (4.53.3)\n", + "Requirement already satisfied: urllib3~=2.5.0 in /usr/local/lib/python3.12/dist-packages (from pyhealth) (2.5.0)\n", + "Requirement already satisfied: click>=8.1 in /usr/local/lib/python3.12/dist-packages (from dask~=2025.11.0->dask[complete]~=2025.11.0->pyhealth) (8.3.1)\n", + "Requirement already satisfied: cloudpickle>=3.0.0 in /usr/local/lib/python3.12/dist-packages (from dask~=2025.11.0->dask[complete]~=2025.11.0->pyhealth) (3.1.2)\n", + "Requirement already satisfied: fsspec>=2021.09.0 in /usr/local/lib/python3.12/dist-packages (from dask~=2025.11.0->dask[complete]~=2025.11.0->pyhealth) (2025.3.0)\n", + "Requirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.12/dist-packages (from dask~=2025.11.0->dask[complete]~=2025.11.0->pyhealth) (26.0)\n", + "Requirement already satisfied: partd>=1.4.0 in /usr/local/lib/python3.12/dist-packages (from dask~=2025.11.0->dask[complete]~=2025.11.0->pyhealth) (1.4.2)\n", + "Requirement already satisfied: pyyaml>=5.3.1 in /usr/local/lib/python3.12/dist-packages (from dask~=2025.11.0->dask[complete]~=2025.11.0->pyhealth) (6.0.3)\n", + "Requirement already satisfied: toolz>=0.10.0 in /usr/local/lib/python3.12/dist-packages (from dask~=2025.11.0->dask[complete]~=2025.11.0->pyhealth) (0.12.1)\n", + "Requirement already satisfied: lz4>=4.3.2 in /usr/local/lib/python3.12/dist-packages (from dask[complete]~=2025.11.0->pyhealth) (4.4.5)\n", + "Requirement already satisfied: axial-positional-embedding in /usr/local/lib/python3.12/dist-packages (from linear-attention-transformer>=0.19.1->pyhealth) (0.3.12)\n", + "Requirement already satisfied: linformer>=0.1.0 in /usr/local/lib/python3.12/dist-packages (from linear-attention-transformer>=0.19.1->pyhealth) (0.2.3)\n", + "Requirement already satisfied: local-attention in /usr/local/lib/python3.12/dist-packages (from linear-attention-transformer>=0.19.1->pyhealth) (1.11.2)\n", + "Requirement already satisfied: product-key-memory>=0.1.5 in /usr/local/lib/python3.12/dist-packages (from linear-attention-transformer>=0.19.1->pyhealth) (0.3.0)\n", + "Requirement already satisfied: lightning-utilities in /usr/local/lib/python3.12/dist-packages (from litdata~=0.2.59->pyhealth) (0.15.2)\n", + "Requirement already satisfied: filelock in /usr/local/lib/python3.12/dist-packages (from litdata~=0.2.59->pyhealth) (3.24.2)\n", + "Requirement already satisfied: boto3 in /usr/local/lib/python3.12/dist-packages (from litdata~=0.2.59->pyhealth) (1.42.53)\n", + "Requirement already satisfied: requests in /usr/local/lib/python3.12/dist-packages (from litdata~=0.2.59->pyhealth) (2.32.4)\n", + "Requirement already satisfied: tifffile in /usr/local/lib/python3.12/dist-packages (from litdata~=0.2.59->pyhealth) (2026.2.16)\n", + "Requirement already satisfied: obstore in /usr/local/lib/python3.12/dist-packages (from litdata~=0.2.59->pyhealth) (0.8.2)\n", + "Requirement already satisfied: decorator in /usr/local/lib/python3.12/dist-packages (from mne~=1.10.0->pyhealth) (4.4.2)\n", + "Requirement already satisfied: jinja2 in /usr/local/lib/python3.12/dist-packages (from mne~=1.10.0->pyhealth) (3.1.6)\n", + "Requirement already satisfied: lazy-loader>=0.3 in /usr/local/lib/python3.12/dist-packages (from mne~=1.10.0->pyhealth) (0.4)\n", + "Requirement already satisfied: matplotlib>=3.7 in /usr/local/lib/python3.12/dist-packages (from mne~=1.10.0->pyhealth) (3.10.0)\n", + "Requirement already satisfied: pooch>=1.5 in /usr/local/lib/python3.12/dist-packages (from mne~=1.10.0->pyhealth) (1.9.0)\n", + "Requirement already satisfied: scipy>=1.11 in /usr/local/lib/python3.12/dist-packages (from mne~=1.10.0->pyhealth) (1.16.3)\n", + "Requirement already satisfied: six>=1.12.0 in /usr/local/lib/python3.12/dist-packages (from ogb>=1.3.5->pyhealth) (1.17.0)\n", + "Requirement already satisfied: outdated>=0.2.0 in /usr/local/lib/python3.12/dist-packages (from ogb>=1.3.5->pyhealth) (0.2.2)\n", + "Requirement already satisfied: python-dateutil>=2.8.2 in /usr/local/lib/python3.12/dist-packages (from pandas~=2.3.1->pyhealth) (2.9.0.post0)\n", + "Requirement already satisfied: pytz>=2020.1 in /usr/local/lib/python3.12/dist-packages (from pandas~=2.3.1->pyhealth) (2025.2)\n", + "Requirement already satisfied: tzdata>=2022.7 in /usr/local/lib/python3.12/dist-packages (from pandas~=2.3.1->pyhealth) (2025.3)\n", + "Requirement already satisfied: polars-runtime-32==1.35.2 in /usr/local/lib/python3.12/dist-packages (from polars~=1.35.2->pyhealth) (1.35.2)\n", + "Requirement already satisfied: annotated-types>=0.6.0 in /usr/local/lib/python3.12/dist-packages (from pydantic~=2.11.7->pyhealth) (0.7.0)\n", + "Requirement already satisfied: pydantic-core==2.33.2 in /usr/local/lib/python3.12/dist-packages (from pydantic~=2.11.7->pyhealth) (2.33.2)\n", + "Requirement already satisfied: typing-extensions>=4.12.2 in /usr/local/lib/python3.12/dist-packages (from pydantic~=2.11.7->pyhealth) (4.15.0)\n", + "Requirement already satisfied: typing-inspection>=0.4.0 in /usr/local/lib/python3.12/dist-packages (from pydantic~=2.11.7->pyhealth) (0.4.2)\n", + "Requirement already satisfied: joblib>=1.2.0 in /usr/local/lib/python3.12/dist-packages (from scikit-learn~=1.7.0->pyhealth) (1.5.3)\n", + "Requirement already satisfied: threadpoolctl>=3.1.0 in /usr/local/lib/python3.12/dist-packages (from scikit-learn~=1.7.0->pyhealth) (3.6.0)\n", + "Requirement already satisfied: setuptools in /usr/local/lib/python3.12/dist-packages (from torch~=2.7.1->pyhealth) (75.2.0)\n", + "Requirement already satisfied: sympy>=1.13.3 in /usr/local/lib/python3.12/dist-packages (from torch~=2.7.1->pyhealth) (1.14.0)\n", + "Requirement already satisfied: nvidia-cuda-nvrtc-cu12==12.6.77 in /usr/local/lib/python3.12/dist-packages (from torch~=2.7.1->pyhealth) (12.6.77)\n", + "Requirement already satisfied: nvidia-cuda-runtime-cu12==12.6.77 in /usr/local/lib/python3.12/dist-packages (from torch~=2.7.1->pyhealth) (12.6.77)\n", + "Requirement already satisfied: nvidia-cuda-cupti-cu12==12.6.80 in /usr/local/lib/python3.12/dist-packages (from torch~=2.7.1->pyhealth) (12.6.80)\n", + "Requirement already satisfied: nvidia-cudnn-cu12==9.5.1.17 in /usr/local/lib/python3.12/dist-packages (from torch~=2.7.1->pyhealth) (9.5.1.17)\n", + "Requirement already satisfied: nvidia-cublas-cu12==12.6.4.1 in /usr/local/lib/python3.12/dist-packages (from torch~=2.7.1->pyhealth) (12.6.4.1)\n", + "Requirement already satisfied: nvidia-cufft-cu12==11.3.0.4 in /usr/local/lib/python3.12/dist-packages (from torch~=2.7.1->pyhealth) (11.3.0.4)\n", + "Requirement already satisfied: nvidia-curand-cu12==10.3.7.77 in /usr/local/lib/python3.12/dist-packages (from torch~=2.7.1->pyhealth) (10.3.7.77)\n", + "Requirement already satisfied: nvidia-cusolver-cu12==11.7.1.2 in /usr/local/lib/python3.12/dist-packages (from torch~=2.7.1->pyhealth) (11.7.1.2)\n", + "Requirement already satisfied: nvidia-cusparse-cu12==12.5.4.2 in /usr/local/lib/python3.12/dist-packages (from torch~=2.7.1->pyhealth) (12.5.4.2)\n", + "Requirement already satisfied: nvidia-cusparselt-cu12==0.6.3 in /usr/local/lib/python3.12/dist-packages (from torch~=2.7.1->pyhealth) (0.6.3)\n", + "Requirement already satisfied: nvidia-nccl-cu12==2.26.2 in /usr/local/lib/python3.12/dist-packages (from torch~=2.7.1->pyhealth) (2.26.2)\n", + "Requirement already satisfied: nvidia-nvtx-cu12==12.6.77 in /usr/local/lib/python3.12/dist-packages (from torch~=2.7.1->pyhealth) (12.6.77)\n", + "Requirement already satisfied: nvidia-nvjitlink-cu12==12.6.85 in /usr/local/lib/python3.12/dist-packages (from torch~=2.7.1->pyhealth) (12.6.85)\n", + "Requirement already satisfied: nvidia-cufile-cu12==1.11.1.6 in /usr/local/lib/python3.12/dist-packages (from torch~=2.7.1->pyhealth) (1.11.1.6)\n", + "Requirement already satisfied: triton==3.3.1 in /usr/local/lib/python3.12/dist-packages (from torch~=2.7.1->pyhealth) (3.3.1)\n", + "Requirement already satisfied: huggingface-hub<1.0,>=0.30.0 in /usr/local/lib/python3.12/dist-packages (from transformers~=4.53.2->pyhealth) (0.36.2)\n", + "Requirement already satisfied: regex!=2019.12.17 in /usr/local/lib/python3.12/dist-packages (from transformers~=4.53.2->pyhealth) (2025.11.3)\n", + "Requirement already satisfied: tokenizers<0.22,>=0.21 in /usr/local/lib/python3.12/dist-packages (from transformers~=4.53.2->pyhealth) (0.21.4)\n", + "Requirement already satisfied: safetensors>=0.4.3 in /usr/local/lib/python3.12/dist-packages (from transformers~=4.53.2->pyhealth) (0.7.0)\n", + "Requirement already satisfied: psutil in /usr/local/lib/python3.12/dist-packages (from accelerate->pyhealth) (5.9.5)\n", + "Requirement already satisfied: Pillow in /usr/local/lib/python3.12/dist-packages (from rdkit->pyhealth) (11.3.0)\n", + "Requirement already satisfied: hf-xet<2.0.0,>=1.1.3 in /usr/local/lib/python3.12/dist-packages (from huggingface-hub<1.0,>=0.30.0->transformers~=4.53.2->pyhealth) (1.2.0)\n", + "Requirement already satisfied: contourpy>=1.0.1 in /usr/local/lib/python3.12/dist-packages (from matplotlib>=3.7->mne~=1.10.0->pyhealth) (1.3.3)\n", + "Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.12/dist-packages (from matplotlib>=3.7->mne~=1.10.0->pyhealth) (0.12.1)\n", + "Requirement already satisfied: fonttools>=4.22.0 in /usr/local/lib/python3.12/dist-packages (from matplotlib>=3.7->mne~=1.10.0->pyhealth) (4.61.1)\n", + "Requirement already satisfied: kiwisolver>=1.3.1 in /usr/local/lib/python3.12/dist-packages (from matplotlib>=3.7->mne~=1.10.0->pyhealth) (1.4.9)\n", + "Requirement already satisfied: pyparsing>=2.3.1 in /usr/local/lib/python3.12/dist-packages (from matplotlib>=3.7->mne~=1.10.0->pyhealth) (3.3.2)\n", + "Requirement already satisfied: littleutils in /usr/local/lib/python3.12/dist-packages (from outdated>=0.2.0->ogb>=1.3.5->pyhealth) (0.2.4)\n", + "Requirement already satisfied: locket in /usr/local/lib/python3.12/dist-packages (from partd>=1.4.0->dask~=2025.11.0->dask[complete]~=2025.11.0->pyhealth) (1.0.0)\n", + "Requirement already satisfied: platformdirs>=2.5.0 in /usr/local/lib/python3.12/dist-packages (from pooch>=1.5->mne~=1.10.0->pyhealth) (4.9.2)\n", + "Requirement already satisfied: colt5-attention>=0.10.14 in /usr/local/lib/python3.12/dist-packages (from product-key-memory>=0.1.5->linear-attention-transformer>=0.19.1->pyhealth) (0.11.1)\n", + "Requirement already satisfied: charset_normalizer<4,>=2 in /usr/local/lib/python3.12/dist-packages (from requests->litdata~=0.2.59->pyhealth) (3.4.4)\n", + "Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.12/dist-packages (from requests->litdata~=0.2.59->pyhealth) (3.11)\n", + "Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.12/dist-packages (from requests->litdata~=0.2.59->pyhealth) (2026.1.4)\n", + "Requirement already satisfied: mpmath<1.4,>=1.1.0 in /usr/local/lib/python3.12/dist-packages (from sympy>=1.13.3->torch~=2.7.1->pyhealth) (1.3.0)\n", + "Requirement already satisfied: botocore<1.43.0,>=1.42.53 in /usr/local/lib/python3.12/dist-packages (from boto3->litdata~=0.2.59->pyhealth) (1.42.53)\n", + "Requirement already satisfied: jmespath<2.0.0,>=0.7.1 in /usr/local/lib/python3.12/dist-packages (from boto3->litdata~=0.2.59->pyhealth) (1.1.0)\n", + "Requirement already satisfied: s3transfer<0.17.0,>=0.16.0 in /usr/local/lib/python3.12/dist-packages (from boto3->litdata~=0.2.59->pyhealth) (0.16.0)\n", + "Requirement already satisfied: distributed==2025.11.0 in /usr/local/lib/python3.12/dist-packages (from dask~=2025.11.0->dask[complete]~=2025.11.0->pyhealth) (2025.11.0)\n", + "Requirement already satisfied: bokeh>=3.1.0 in /usr/local/lib/python3.12/dist-packages (from dask~=2025.11.0->dask[complete]~=2025.11.0->pyhealth) (3.7.3)\n", + "Requirement already satisfied: msgpack>=1.0.2 in /usr/local/lib/python3.12/dist-packages (from distributed==2025.11.0->dask~=2025.11.0->dask[complete]~=2025.11.0->pyhealth) (1.1.2)\n", + "Requirement already satisfied: sortedcontainers>=2.0.5 in /usr/local/lib/python3.12/dist-packages (from distributed==2025.11.0->dask~=2025.11.0->dask[complete]~=2025.11.0->pyhealth) (2.4.0)\n", + "Requirement already satisfied: tblib>=1.6.0 in /usr/local/lib/python3.12/dist-packages (from distributed==2025.11.0->dask~=2025.11.0->dask[complete]~=2025.11.0->pyhealth) (3.2.2)\n", + "Requirement already satisfied: tornado>=6.2.0 in /usr/local/lib/python3.12/dist-packages (from distributed==2025.11.0->dask~=2025.11.0->dask[complete]~=2025.11.0->pyhealth) (6.5.1)\n", + "Requirement already satisfied: zict>=3.0.0 in /usr/local/lib/python3.12/dist-packages (from distributed==2025.11.0->dask~=2025.11.0->dask[complete]~=2025.11.0->pyhealth) (3.0.0)\n", + "Requirement already satisfied: MarkupSafe>=2.0 in /usr/local/lib/python3.12/dist-packages (from jinja2->mne~=1.10.0->pyhealth) (3.0.3)\n", + "Requirement already satisfied: hyper-connections>=0.1.8 in /usr/local/lib/python3.12/dist-packages (from local-attention->linear-attention-transformer>=0.19.1->pyhealth) (0.4.9)\n", + "Requirement already satisfied: xyzservices>=2021.09.1 in /usr/local/lib/python3.12/dist-packages (from bokeh>=3.1.0->dask~=2025.11.0->dask[complete]~=2025.11.0->pyhealth) (2025.11.0)\n", + "Requirement already satisfied: torch-einops-utils>=0.0.20 in /usr/local/lib/python3.12/dist-packages (from hyper-connections>=0.1.8->local-attention->linear-attention-transformer>=0.19.1->pyhealth) (0.0.30)\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "## **Exploring [pyhealth.datasets](https://pyhealth.readthedocs.io/en/latest/api/datasets.html) (e.g., MIMIC-III, COVID19CXR)**\n", + "- **[README]**: The PyHealth dataset module is used to process the unstructured raw data into a structured dataset object. Here, we showcase how pyhealth datasets work (i.e how to work with the BaseDataset class) and how it simplifies much of the heavy lifting in doing experimental research while being minimally invasive.\n", + "- **[Arguments]**:\n", + " - `root` is the arguments directing to the data folder, e.g., \"mimiciii/1.4/\".\n", + " - `tables` is a list of table names from raw databases, which specifies the information that will be used in building your dataset.\n", + " - ``dev``: whether to enable dev mode (only use a small subset of the data)\n", + " Default is False.\n", + "\n", + "- **[Functionality]**: currently, we provide the api for:\n", + " - [MIMIC3Dataset](https://pyhealth.readthedocs.io/en/latest/api/datasets/pyhealth.datasets.MIMIC3Dataset.html)\n", + " - [MIMIC4Dataset](https://pyhealth.readthedocs.io/en/latest/api/datasets/pyhealth.datasets.MIMIC4Dataset.html)\n", + " - [eICUDataset](https://pyhealth.readthedocs.io/en/latest/api/datasets/pyhealth.datasets.eICUDataset.html)\n", + " - [OMOPDataset](https://pyhealth.readthedocs.io/en/latest/api/datasets/pyhealth.datasets.OMOPDataset.html): any OMOP-CDM based databases." + ], + "metadata": { + "id": "_1S5rqae7FhB" + } + }, + { + "cell_type": "markdown", + "source": [ + "![image.png](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABlAAAAGoCAYAAAA5EqguAAAACXBIWXMAABYlAAAWJQFJUiTwAAAgAElEQVR4nOzdeVyU1f4H8M8wgKyisnhBZRFlUcRcyQUdxDT3LAvc7dpiVnptMft1b3lbfi1mZmXXe7uVpl5zSc3dTMHMBRUFFTFFQZRNRGSHYWbO7w9/zPWZBQYYGJbP+/Xilc/znOec7znPBDPPd85zZEIIASIiIiIiIiIiIiIiItKysnQARERERERERERERERETQ0TKERERERERERERERERDqYQCEiIiIiIiIiIiIiItLBBAoREREREREREREREZEOJlCIiIiIiIiIiIiIiIh0MIFCRERERERERERERESkgwkUIiIiIiIiIiIiIiIiHUygEBERERERERERERER6bC2dABERERERERERER1oVarkZKSgqSkJFy8eBFJSUlQqVQICAhAUFAQhg0bBj8/vxrruXz5Mtzc3ODm5tYIUTe+lt6/mly7dg0rVqyAk5MTFi5cCE9Pz2bZRlFREa5fv47evXubve6mpjX1lZo2JlCIiIiIiIiIiKjZOXfuHGbOnImkpCSjZWxsbPD888/j7bffhru7u8Eyc+bMwdq1a9GmTRusXLkSzz//fEOFbBEtvX+mePnll7Fv3z4AQHFxMb766qtm18b58+cxdOhQFBUVISQkBMePH4ezs7NZ22gqWlNfqenjI7yIiIiIiIiIiKhZWblyJcLCwqpNngBAZWUlvvrqKwwaNAh3797VO15cXIx169YBACoqKrB8+fIGiddSWnr/TPXbb79p/3306NFm2caGDRtQVFQEALh48SJ27dpl9jaaitbUV2r6mEAhIiIiIiIiIqJmIzk5Ga+88goqKysl+7t3745nn30Wc+fO1Xt80rVr1/D000/r1VVYWAiNRqPdNpRkac5aev9ModFoUFJSot2uqKholm3k5+dLtlvytWxNfaWmj4/wIiIiIiIiIiKiZmP16tWSpEDXrl2xb98+BAQEaPeVl5cjIiICJ0+e1O7bu3cviouL4eTkpN2nUqkkdetuN3ctvX+tSWu6lq2pr9T0cQYKERERERERERE1G5cuXZJs/+Uvf5EkTwDAzs4OP/74I9q1a6fdp1KpkJGRUed2VSoVbt++LdmnVCpx8+ZNg+UrKiqQm5tbY705OTl6s2mMUSqV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69e+ffskN/XlcjnWrl2LadOmScb4k08+kZyn+2i7p556Ch999BEA4MSJE5JzhwwZAmdnZwwfPhyOjo4oKSkBACxevFiS4IqOjja5T+YaS3P1vyaN1Q4REREREREREVFd8C5UKxQUFCTZvnXrFubNm2ew7NGjR7F161bJPn9//waJa+zYsXjppZcwYsQIySOMunXrhtdeew3r1q2TlM/JyZHcaNZd28XY+gkPqumb/bqP07px44beN/e//vpr7c1vQ4KDgyXbK1asQGVlpV65d999VzvWubm5krUyANP6Z454ddU0Rrr9279/v9E1Vj755BM4OzvDw8NDOzND9/WYkpKC9evX65374YcfmhyzKarrV3x8vGRboVBg+vTpkpv6FRUViImJkZTTTVg9uHaJWq3G0aNHtdtjxowBcH+21siRI7X7H0wotGvXDqNGjTKlOwDMN5bm6L8pr1dzjTMREREREREREVFDYAKlFXrmmWfg6ekp2bd+/XoMGzYMf/3rX/Hzzz9j3bp1eOmllxAREaG3YPPTTz9t9piEENpZEUIIREVF4eTJk5IyuuuqhIaGSmbN6Pbp+PHjUKlUUCqVkkdo1YZunZWVlXjhhReQkpKC3NxcfPnll1i0aFG1dTzzzDOS2Q43btzAmDFjtDeB7927h08//RTvvPOO5LyAgIBqYzHUP3PEW1tz585F27ZttdtHjhzB66+/LilTVlaG5557Dm+88QaUSiUKCgpw8eJFAEBISAgUCoWk/LPPPosNGzagqKgIWVlZePfdd/Hll1+aNe7q6L7WEhISJAmAoqIijB8/Hnl5eZJyly9flmw/9NBDetexStUjzABg3LhxBstMnjy5xhlADzLXWJqj/x4eHpKZIkqlEnFxcQDuP8ZOCGG2cSYiIiIiIiIiImoIfIRXK+Tk5ISPPvoIs2fPluw/evSo5BvyhgwZMgSzZs0ye0wymQzR0dH4+uuvAQAlJSWIjIxEeHg4+vXrh9TUVOzfv19yTtU3+KvoJg92796N9u3bo7S0FHK5HBs3bkS7du1qFVevXr3QqVMnZGRkaPft27fP6BofhgQGBuKNN97Ae++9p9136NAheHl5oVOnTsjOztZLUoWFhWHo0KGSfab0b/LkyfWOt7a8vLzw/vvvY8GCBdp9y5cvx/79+zFixAioVCps3bpV8sgoDw8PREZGarffe+89hIeHa7fLy8sxY8YMyOVyaDQaozNaGsro0aMl23l5efD398fkyZNx584dHDlyRG/BdgDaBMGDoqKiJNceuL8OUWhoqHZ73LhxkMlkev2cOnVqrWM3x1iao/9yuRweHh6SdVgGDRoEJycnFBUVoV+/fnqzY+ozzkRERERERERERGYnqFXSaDTizTffFG3atBEATPp59NFHRU5OjsH6xowZoy1nZWVlsFxqaqqkvujoaMnxW7duiUGDBpkUS2BgoLhx44bk/LS0NOHi4mL0nBdeeEFcv35dsu+pp56qcaw2bdokrK2tjdbr6ekp5s+fL9l37tw5SR1lZWVi5syZJvctOztbLw5T+meOeOsyRmq1WixYsEBYWVnV2D8XFxcRHx+vV8cHH3wgZDKZ0fPc3NzE888/L9kXGxtbY2xVZs2aJTn30qVL1ZafPn16tf2wtrYWM2bMEM7OzpL9utfu6tWreuPy3nvv6bX38MMPS8p07txZqNVqk/v3IHOMpTn6v3DhwmrryMnJMds4ExERERERERERmRsTKK3c9evXRVRUlHBycjJ489LKykr06tVL7Nq1q9p61q9fL+RyuQAgRo8ebbRceHi4ACDkcrnYvn273vHKykrx9ttvi+7du+vddJbJZMLHx0csWbJElJWVGax/y5YtBpMMvr6+IjExUQghxODBg7U3Znfs2GHSOO3evVt07dpVL57p06eLGzduiGvXrgkHBwcBQAQEBBitZ+/evaJXr14GExy+vr5i1apVQqlUGj3flP6ZI966jJEQQpw4cUKEhYUJGxsbvRgdHR3FK6+8YjQJJ4QQO3bsEH5+fnpxP/HEEyIlJUXcunVL+1rt1KmTqKysNDm2PXv2aMe9f//+NZbXaDTitdde0xtvOzs7MWrUKHHhwgUhxP2EVVV/hwwZIjQajV5dDyYSQkJCREZGhl6ZI0eOaOOTyWRi48aNJvfNkPqOpTn6X15eLkaMGKH3WpDL5WLBggVmH2ciIiIiIiIiIiJzkgnRyM/GoSbr1q1buHz5MvLz8+Hk5AR/f3/4+vqavAZDamoq0tPTMWzYMMki0A8SQiAmJgbdu3dHly5dqq2vtLQUSUlJuHnzJvz8/BAYGAgHB4ca41AqlTh+/Dhyc3Ph6OiITp06ITQ0VBuTRqPB4cOHERQUhM6dO5vUtypZWVm4dOkSnJ2d0b17d7Rv3157LD8/HydPnkRkZGSNY6ZUKnH16lVkZmbC1dUVAQEBcHJyMimGmvpnjnjrM0YAoFKpkJKSgitXrsDR0VF7vY29LgzFffr0abi4uCAoKAgdO3bUHisoKMCxY8cwYsSIGhe415WRkYHk5GSMGDFCsj5HdTQaDS5duoSrV68iICAAgYGBsLaWPv3w5s2buHr1KhQKhcF6hRA4ffo0SkpKoFAojI5DXl4ejh07hv79+8PLy6tWfTOmvmNpjv6npaUhISEBarUaHTp0QO/evdGhQwezt0NERERERERERGROTKAQERERERERERERERHp4Fd4iYiIiIiIiIiIiIiIdDCBQkREREREREREREREpIMJFCIiIiIiIiIiIiIiIh1MoBAREREREREREREREelgAoWIiIiIiIiIiIiIiEgHEyhEREREREREZBKZTFbtT1pamt45S5cuNVp+6dKleuXT0tKqbcOQOXPm1KqN2NhYo+V9fX0NtqFQKIyes2bNGr3ya9asMVpeoVAYbMPX19foObGxsbUa2zlz5hhsg9eP14/XT2GwDV4/Xj9eP1+DbTS362dsrOqKCRQiIiIiIiIiIiIiImr2Zs+ebdb6ZEIIYdYaiYiIiIiIiKhFqvpWJ28lEBERUWtgbekAiIiIiIiIiKh5iImJsXQIRERERI2GM1CIiIiIiIiIiIiIiIh0cA0UIiIiIiIiIiIiIiIiHUygEBERERERERERERER6WAChYiIiIiIiIiIiIiImjWZTAaZTGbWOplAISIiIiIiIiKTLF26FEuXLrV0GERERESNgovIExEREREREZFJqr7VyVsJRERE1NQ0xPsUzkAhIiIiIiIiIiIiIiLSwQQKERERERERERERERGRDiZQiIiIiIiIiIiIiIiIdDCBQkREREREREREREREpMPa0gEQERERERERERERERHVR2pqqtnrZAKFiIiIiIiIiEwye/ZsS4dAREREZJCvr6/Z65QJIYTZayUiIiIiIiIiIiIiImrGuAYKERERERERERERERGRDiZQiIiIiIiIiIiIiIiIdDCBQkREREREREREREREzdrSpUuxdOlSs9bJNVCIiIiIiIiIiIiIiKhZk8lkAABzpjwaZAaKTCYz+pOWlqZXfunSpUbLG8oYpaWlVduGIXPmzKlVG7GxsUbL+/r6GmxDoVAYPWfNmjV6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//73v86fzWYzDz30EPfffz/h4eH1WoayoVVeGODOilnV74lIg7n22mv54IMPCAoKYvHixYwdO9Z5RdWFbMeOHQwaNIhZs2bx008/uSQsoKIU8oMPPuDqq6/mueeeczlIKSsrY9asWc4djfLycpKTk/n666+rzfHCCy84r4grKSnh66+/ZuXKlW6LZdWqVSxZsqRa8qTyeceOHeP7779n3LhxTJo0qV7v0fHjxxk7diyTJk1iy5YtzuRJ5bZ89913PP300wwfPpxjx465PHfevHns3LmzWvIEoKioiB07dvDPf/6Tbt26sWjRIpfH//Of/7B+/XrKy8sByM3N5Zlnnqk2z3vvvcfWrVspKysDID09nZdffrle23iq5ORk55WJa9euPet5FixYwJYtW1ixYgVvv/32b4pJRERExFs5HA7Ky8spLS11+VO5nwcQGxtLYmIiAG+//TZffvklFouFxx57DIDg4GCaNWsGVJzY+/jjj1m/fj3r169n2bJlTJ482fl4VWeq0qh83G63O/evx4wZw+7du1m3bh1r164lNTWVBx98sMYL0C655BIA4uPjWbp0KRs2bGDDhg2sWLGC++67j/j4eAA6dOhAYmIiJ0+e5LXXXmPz5s2YTCamTp0KQHh4OFFRUQD069ePr776ig0bNrB+/Xo+/vhjbrnlFkJDQ+u1bY1dma2ElMzlHC7YX2PyBCp+dwpKc0jet5jck8fPcYT153DY2XPiR9Yf+IJye1m15Eklu8POz9nb2H5kLVZ72TmO0vsFtelBeWE2JUf3eTqUanzMRrrGh9byydfO12Li0raRDRJTfXTr1o1XXnmFTZs2MXz4cOfFob3bRmCz1z9pGxXi57EG8pVCQkLo1q0b//73v1m/fj2DBg3C19eXQF8zHaJD6t3bxQEMu8SzK1WYTCZiY2O5++672bdvH0899RRNmzZtVMkTgFatWtGqVSu3zqkEiog0qP79+/PZZ58RHh7OF198wY033ljjCfcLRVFRESNHjmTr1q3O+5o1a8aIESMYNWoUkZG/7rzY7XaeeOIJ5s+f77yvvLy8xsTAsmXLXG6vW7eOgoKCauMOHjzotlgqy/orjRw5ktGjR3PVVVdVq55YtGgRS5Ysqf6G1GL8+PF8+umnzttRUVGMGDGCkSNH0qRJE+f969evJzEx0SUxt2/fPpfn9enTh4svvthleyq3/95772XPnj3O+2pK8G3fvp3MTNeGgae+31D96pn6qrySEHA5sK+v/Px858+nrikrIiIi8lvNnDmzUa88UXmCPy8vj9dee40nn3ySJ598kqeeeoqnnnqKp59+muTkZOf42267DYPBQF5eHhkZGQwePJjWrVs7Hx85ciRQsfb7yy+/zKZNm1i/fj0PPfQQN9xww1ldsFKZlCgoKOCrr75iyZIl7N27l3bt2nHZZZdx+eWX06FDh1qr96+77joiIyPZtm0b8+bNIyUlhe+++46//OUvjB49mocfftg59s9//jMAR48eJSsri1GjRhEXF+d8/O677wYqjh8WLlzI9u3bWb58OVOmTGHMmDF88sknLq/t7RUoO45+z6H8fdRlYaBSawk/ZH5FidVzDZLtdjs5OTnOC7dqcrzoELuOp2CsQ48Tu8PGz1nbOFKQ7s4w662srKza8nCNnW94DH6RcRTsWu/pUKrx8zEx+KJmBPjU/US2wwGDL2pG0xDPLdkdEBDAE088wbJly7jnnnsICnJdNm/wRc2IDQ+o97zd48Jo2zzYXWHWW2xsLE888QTr1q1j3LhxLkuQG40GLmndhLjI+m1XRJAPv+8X7+5Q62XEiBF88MEH/POf/zyv+53URGvpiEiD69GjB19++SXXX3893377LcOGDeOjjz4iIsJ7yqHdZfbs2S47imPGjOHll18mIKDiy9PhcLBo0SLuuusu58HJ3//+d4YPH37apZiqHgRCRXXIuY7l1Vdfxd/f33n766+/ZtSoUc7bn3/+eZ2WuHr33Xf59ttvnbeHDRvGG2+84dyZstvtTJ8+nTfffBOAzMxMPvvsM5fXqnTTTTfx9NNPO28XFxfz1ltv8eijj2K1Wjl58iSTJk1i+fLlp11ebtWqVYwbNw6AwsJCUlJSzrgdnlI1webtB7giIiLS+FRWZzTWJErlMUZeXh7/+te/ahwzaNAgZ+VJ165dGT58OJ9++ikmk4lbb73VZezo0aPZsWMHc+fO5aWXXuLDDz+kvLycffv20bVrV+dyKr6+vgQGVlzxHBz864m78PBwoGL9+8qTaAkJCURGRnLixAn+/ve/YzKZuP3223nppZeqxVp58ZDJZHLur1500UX87W9/4/HHH+f555/ngw8+wGazkZaWRnh4uMv+72WXXcbAgQNZvXo1FouFP/3pTy7z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7apNBxctWsR3330HVCQT0tPTXfqvmEwmXn311dNWXAwYMKDafXVN2FSNaerUqcyaNcu5TVarlaFDh7JlyxZef/31Gp9XtefKmjVr2LZtG23atCE5OZmpU6e6jE1NTWXYsGEu/Vy+/vprlixZQnZ2drU+QgsXLmT69OkcPXqUZ599ltWrVzsf27NnDzabTZUoF6D09HRPhyAiIiLSoEJ8wxnQaiR7szaTkbsbq60Mu8OGwWDEbLQQFRhLh6heBPl4rkdIfRkMBjo07UlEQHNSj28kryQLm73iAi2jwUigTwhtIrrTMqx9nZcvk7ppfuUdbH64H037j8ES0tTT4Yhc8Covyq26xP1vpQSKiHjU8ePHad68eY2NrE/1wgsvcOutt9a7WXhjd+ykQgAAH89JREFUEhAQwOeff87kyZP54YcfgIqr/T/99NNqYwMDA3nqqae4+eabnfdZLBYsFouzIqMymTF06FCXBMrAgQMxm83OearO6a5YqlZUBAYGulQ+/Bb+/v589NFHjB49mj179gBQWFhYrT8OQMeOHVmwYIFzW6Giuqby9+nEiRO1VlP4+fkxe/Zsl+qTmt6rli1b0q5dO2csULH8FeCSTDpTYmnatGm89957zsTQ+++/79JTpVmzZhw9ehTAWaJ/ww03kJSUhN1uJzMzk379+mEwGJwJx5CQEGfV0MaNGwHo1KmTc8709HRuv/12AHr27Em/fv2cfU6ef/555syZU+NcxcXF7Nixg27dup12m0REROTCU7nihCoWxZv5mPzoHNWXDpG9yCvNotxWislgJsgnFD9L4JknaKQiA2PoF9iCorJ8issq9u39zAEE+TbBaHD7IjQC+IQ1I2bE/RxZvpCWN3r3BZ8i54O33noLcG8CRf97iohH3X777WzevJkXX3yR2NjY044tLi7m//7v/85RZA2nTZs2fPXVV8ycOZPu3bvj5+daPh0TE8OIESNYt24df/jDH1we8/HxYfDgwQD06NHDWW0wfPhw54lzi8XisjxXZX+PgICAatUUvyWWwYMHExpasR7wyJEj3Vqt0KpVK1asWMGDDz5IdHS0y2MGg4H4+Hj+9Kc/sWbNmmpN7e+//37Cw8OrzWkwGAgLC6NTp05MnTqVdevWuSwXBnDllVdiNpsxGo1cddVVzvv//Oc/O38eOnQo3bt3Byr6wURERACn76MC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Ig3O7QmUtLQ0ABISEtw5rYiIiIg0sAkTJgCQlJTk0ThERERE5PxWnn+C0qxM7GUlmPyC8G0a59Em5G7hsFN6IpOy3CMAmIMj8YuKr1svkUbMVlJIydE0bCWFGH388I2MwxIc7umwRM4ZtydQRERERMQ7qZJYREREREREvNXMmTNd/nYHJVBEREREBFACRURERERERLxXQxzTetfieyIiIiIiIiLiMQkJCVqyW0RERC4YqkAREREREUAVKCIicmb6rhAREZHGyisqUGbOnOnWNcZERERERERERERERETONbdXoOhqFBERERHvpP04ERE5E31XiIiISGPVEPspZrfNJCIiIiJebcaMGZ4OQURERERERKTRUAWKiIiIiIiIiNSJjvlFRESksZowYQIASUlJbptTCRQRERERERERqRMd84uIiMiFREt4iYiIiIiIiEidrFq1ytMhiIiIiJwzqkARERERERERERERERE5hdsrUNR8VERERMQ7JScnA5CYmOjROEREREREREQaA7dXoIiIiIiId1IlsYiIiIiIiMivjJ4OQERERERERERERERE5LcwGAzOCwPdRQkUEREREREREamTmTNnMnPmTE+HISIiInJOaAkvEREREQG0hJeIiJyZvitERESksWqI/RS3V6CkpaWRlpbm7mlFRERERERERERERETOGbdXoOhqFBERERHvpP04ERE5E31XiIiISGPVEPspZrfNJCIiIiJeLT4+3tMhiIiIiIiIiDQaqkARERERERERkTrRMb+IiIg0VqpAEREREREREREREREROcX+/fvdPqcSKCIiIiIiIiJSJ+PHj/d0CCIiIiI1SkhIcPucWsJLRERERERERERERETkFEZPByAiIiIiIiIiIiIiItLYuH0JL1WeiIiIiHinxMREAJKTkz0ah4iIiIiIiEhj4PYlvERERETEO2kpVhEREREREfFWM2fOdPnbHZRAERERERFACRQRERERERHxXg1xTKseKCIiIiIiIiJSJwaDwXlyQkREROR8pwSKiIiIiIiIiIiIiIjIKdyeQJkwYQITJkxw97QiIiIiIiIiIiIiIiLnjNt7oGjtbBERERHvpP04ERE5E31XiIiISGPVEPspZrfNJCIiIiJebeHChZ4OQURERERERKTRUAJFRERERAC0DKuIiIiIiIh4rRkzZrh9Ti3hJSIiIiIiIiJ1omN+ERERuZCoAkVERERERERE6mT//v2eDkFERETknFEFioiIiIiIiIiIiIiIyCncXoHSEOuMiYiIiEjDS0pKAtQLRURERERERAQaoAJFRERERLyTKolFRERERETEW6WlpQGQkJDgtjmNbptJRERERERERM57M2fOxGAw1Phn5syZ1canpaXVOr4yeX+qCRMm1Os1kpOTax1f20mUxMTEWp9TWZVZVVJSUq3jExMTa3yNhISEWp+TnJxcr/e2tgrR0723lSeS6voa+vxc6fPT56fPL6HG19Dnp8+vsX5+rVq1olWrVjWOP1tKoIiIiIiIiIiIiIiIiJxCS3iJiIiICKAlvERERERERESqcnsFSnJyco1lOCIiIiIiIiIiIiIiIt7C7RUounJRRERExDtpP05ERERERETkV2ZPByAiIiIijcPAgQM9HYKIiIiIiIhIo/H/7XtUmk5u5CwAAAAASUVORK5CYII=)" + ], + "metadata": { + "id": "MKy5JUKMDIKp" + } + }, + { + "cell_type": "markdown", + "source": [ + "### **Example 1: MIMIC-III**\n", + "- **[Initialize]:** In this example, we load the MIMIC-III data by [pyhealth.datasets.MIMIC3Dataset](https://pyhealth.readthedocs.io/en/latest/api/datasets/pyhealth.datasets.MIMIC3Dataset.html).\n", + "\n", + " - The root of this datasets is in (we use a synthetic MIMIC-III for demo)\n", + " - `https://storage.googleapis.com/pyhealth/Synthetic_MIMIC-III/`.\n", + " - For each patient's ICU stay, user wants to obtain the `DIAGNOSES_ICD`, and `PROCEDURES_ICD` tables. **Note that, different databases have different raw table names**.\n", + "\n" + ], + "metadata": { + "id": "xfYVXbMHX_cE" + } + }, + { + "cell_type": "code", + "source": [ + "from pyhealth.datasets import MIMIC3Dataset\n", + "dataset = MIMIC3Dataset(\n", + " root=\"https://storage.googleapis.com/pyhealth/Synthetic_MIMIC-III\",\n", + " tables=[\"diagnoses_icd\", \"procedures_icd\", \"prescriptions\", \"noteevents\"]\n", + ")" + ], + "metadata": { + "id": "5qKMacix0RE_", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "88de5f57-7ba5-41c8-e0f0-f867770cd601" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "No config path provided, using default config\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.datasets.mimic3:No config path provided, using default config\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Initializing mimic3 dataset from https://storage.googleapis.com/pyhealth/Synthetic_MIMIC-III (dev mode: False)\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "/usr/local/lib/python3.12/dist-packages/pyhealth/datasets/mimic3.py:50: UserWarning: Events from prescriptions table only have date timestamp (no specific time). This may affect temporal ordering of events.\n", + " warnings.warn(\n", + "INFO:pyhealth.datasets.base_dataset:Initializing mimic3 dataset from https://storage.googleapis.com/pyhealth/Synthetic_MIMIC-III (dev mode: False)\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "- **[Output]:** user can check the data loaded by the `.stats()` function. The output `dataset` effectively contains a table of patients, each containing a set of events, defined by the loaded tables." + ], + "metadata": { + "id": "2z2nf68aslx9" + } + }, + { + "cell_type": "code", + "source": [ + "dataset.stats()" + ], + "metadata": { + "id": "wdDj0xEBsfPS", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 974 + }, + "outputId": "c8f4cab3-009a-4121-e1d5-fe864f02dc7b" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "No cache_dir provided. Using default cache dir: /root/.cache/pyhealth/3b3dd072-c3a0-53d4-90cd-e62cb8e1294a\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.datasets.base_dataset:No cache_dir provided. Using default cache dir: /root/.cache/pyhealth/3b3dd072-c3a0-53d4-90cd-e62cb8e1294a\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Scanning table: patients from https://storage.googleapis.com/pyhealth/Synthetic_MIMIC-III/PATIENTS.csv.gz\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.datasets.base_dataset:Scanning table: patients from https://storage.googleapis.com/pyhealth/Synthetic_MIMIC-III/PATIENTS.csv.gz\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Downloading https://storage.googleapis.com/pyhealth/Synthetic_MIMIC-III/PATIENTS.csv to /root/.cache/pyhealth/3b3dd072-c3a0-53d4-90cd-e62cb8e1294a/tmp/48ffef21-7439-4890-8275-18b800666e37/PATIENTS.csv\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.datasets.base_dataset:Downloading https://storage.googleapis.com/pyhealth/Synthetic_MIMIC-III/PATIENTS.csv to /root/.cache/pyhealth/3b3dd072-c3a0-53d4-90cd-e62cb8e1294a/tmp/48ffef21-7439-4890-8275-18b800666e37/PATIENTS.csv\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Scanning table: admissions from https://storage.googleapis.com/pyhealth/Synthetic_MIMIC-III/ADMISSIONS.csv.gz\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.datasets.base_dataset:Scanning table: admissions from https://storage.googleapis.com/pyhealth/Synthetic_MIMIC-III/ADMISSIONS.csv.gz\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Downloading https://storage.googleapis.com/pyhealth/Synthetic_MIMIC-III/ADMISSIONS.csv to /root/.cache/pyhealth/3b3dd072-c3a0-53d4-90cd-e62cb8e1294a/tmp/33c98d9d-0cd8-4e8a-96ad-2cb326142f2e/ADMISSIONS.csv\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.datasets.base_dataset:Downloading https://storage.googleapis.com/pyhealth/Synthetic_MIMIC-III/ADMISSIONS.csv to /root/.cache/pyhealth/3b3dd072-c3a0-53d4-90cd-e62cb8e1294a/tmp/33c98d9d-0cd8-4e8a-96ad-2cb326142f2e/ADMISSIONS.csv\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Scanning table: icustays from https://storage.googleapis.com/pyhealth/Synthetic_MIMIC-III/ICUSTAYS.csv.gz\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.datasets.base_dataset:Scanning table: icustays from https://storage.googleapis.com/pyhealth/Synthetic_MIMIC-III/ICUSTAYS.csv.gz\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Downloading https://storage.googleapis.com/pyhealth/Synthetic_MIMIC-III/ICUSTAYS.csv to /root/.cache/pyhealth/3b3dd072-c3a0-53d4-90cd-e62cb8e1294a/tmp/2a77d8e8-a14d-4116-a2ed-275f2dc9db3a/ICUSTAYS.csv\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.datasets.base_dataset:Downloading https://storage.googleapis.com/pyhealth/Synthetic_MIMIC-III/ICUSTAYS.csv to /root/.cache/pyhealth/3b3dd072-c3a0-53d4-90cd-e62cb8e1294a/tmp/2a77d8e8-a14d-4116-a2ed-275f2dc9db3a/ICUSTAYS.csv\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Scanning table: diagnoses_icd from https://storage.googleapis.com/pyhealth/Synthetic_MIMIC-III/DIAGNOSES_ICD.csv.gz\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.datasets.base_dataset:Scanning table: diagnoses_icd from https://storage.googleapis.com/pyhealth/Synthetic_MIMIC-III/DIAGNOSES_ICD.csv.gz\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Downloading https://storage.googleapis.com/pyhealth/Synthetic_MIMIC-III/DIAGNOSES_ICD.csv to /root/.cache/pyhealth/3b3dd072-c3a0-53d4-90cd-e62cb8e1294a/tmp/b980ed68-ca6b-41f1-b01f-bcf78146df96/DIAGNOSES_ICD.csv\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.datasets.base_dataset:Downloading https://storage.googleapis.com/pyhealth/Synthetic_MIMIC-III/DIAGNOSES_ICD.csv to /root/.cache/pyhealth/3b3dd072-c3a0-53d4-90cd-e62cb8e1294a/tmp/b980ed68-ca6b-41f1-b01f-bcf78146df96/DIAGNOSES_ICD.csv\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Joining with table: https://storage.googleapis.com/pyhealth/Synthetic_MIMIC-III/ADMISSIONS.csv.gz\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.datasets.base_dataset:Joining with table: https://storage.googleapis.com/pyhealth/Synthetic_MIMIC-III/ADMISSIONS.csv.gz\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Downloading https://storage.googleapis.com/pyhealth/Synthetic_MIMIC-III/ADMISSIONS.csv to /root/.cache/pyhealth/3b3dd072-c3a0-53d4-90cd-e62cb8e1294a/tmp/33b458ea-fc2b-437e-a1f2-1a83c9809500/ADMISSIONS.csv\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.datasets.base_dataset:Downloading https://storage.googleapis.com/pyhealth/Synthetic_MIMIC-III/ADMISSIONS.csv to /root/.cache/pyhealth/3b3dd072-c3a0-53d4-90cd-e62cb8e1294a/tmp/33b458ea-fc2b-437e-a1f2-1a83c9809500/ADMISSIONS.csv\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Scanning table: procedures_icd from https://storage.googleapis.com/pyhealth/Synthetic_MIMIC-III/PROCEDURES_ICD.csv.gz\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.datasets.base_dataset:Scanning table: procedures_icd from https://storage.googleapis.com/pyhealth/Synthetic_MIMIC-III/PROCEDURES_ICD.csv.gz\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Downloading https://storage.googleapis.com/pyhealth/Synthetic_MIMIC-III/PROCEDURES_ICD.csv to /root/.cache/pyhealth/3b3dd072-c3a0-53d4-90cd-e62cb8e1294a/tmp/fb9376f3-9f0f-4a9f-a181-59da74fd50e9/PROCEDURES_ICD.csv\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.datasets.base_dataset:Downloading https://storage.googleapis.com/pyhealth/Synthetic_MIMIC-III/PROCEDURES_ICD.csv to /root/.cache/pyhealth/3b3dd072-c3a0-53d4-90cd-e62cb8e1294a/tmp/fb9376f3-9f0f-4a9f-a181-59da74fd50e9/PROCEDURES_ICD.csv\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Joining with table: https://storage.googleapis.com/pyhealth/Synthetic_MIMIC-III/ADMISSIONS.csv.gz\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.datasets.base_dataset:Joining with table: https://storage.googleapis.com/pyhealth/Synthetic_MIMIC-III/ADMISSIONS.csv.gz\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Downloading https://storage.googleapis.com/pyhealth/Synthetic_MIMIC-III/ADMISSIONS.csv to /root/.cache/pyhealth/3b3dd072-c3a0-53d4-90cd-e62cb8e1294a/tmp/c4463a4f-b179-43b4-8185-6e863a36426a/ADMISSIONS.csv\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.datasets.base_dataset:Downloading https://storage.googleapis.com/pyhealth/Synthetic_MIMIC-III/ADMISSIONS.csv to /root/.cache/pyhealth/3b3dd072-c3a0-53d4-90cd-e62cb8e1294a/tmp/c4463a4f-b179-43b4-8185-6e863a36426a/ADMISSIONS.csv\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Scanning table: prescriptions from https://storage.googleapis.com/pyhealth/Synthetic_MIMIC-III/PRESCRIPTIONS.csv.gz\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.datasets.base_dataset:Scanning table: prescriptions from https://storage.googleapis.com/pyhealth/Synthetic_MIMIC-III/PRESCRIPTIONS.csv.gz\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Downloading https://storage.googleapis.com/pyhealth/Synthetic_MIMIC-III/PRESCRIPTIONS.csv to /root/.cache/pyhealth/3b3dd072-c3a0-53d4-90cd-e62cb8e1294a/tmp/e0fb7026-fed3-4c3d-829e-071026f00607/PRESCRIPTIONS.csv\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.datasets.base_dataset:Downloading https://storage.googleapis.com/pyhealth/Synthetic_MIMIC-III/PRESCRIPTIONS.csv to /root/.cache/pyhealth/3b3dd072-c3a0-53d4-90cd-e62cb8e1294a/tmp/e0fb7026-fed3-4c3d-829e-071026f00607/PRESCRIPTIONS.csv\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Joining with table: https://storage.googleapis.com/pyhealth/Synthetic_MIMIC-III/ADMISSIONS.csv.gz\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.datasets.base_dataset:Joining with table: https://storage.googleapis.com/pyhealth/Synthetic_MIMIC-III/ADMISSIONS.csv.gz\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Downloading https://storage.googleapis.com/pyhealth/Synthetic_MIMIC-III/ADMISSIONS.csv to /root/.cache/pyhealth/3b3dd072-c3a0-53d4-90cd-e62cb8e1294a/tmp/5356bbfc-1bfc-45f0-a6f3-691bff93fe5a/ADMISSIONS.csv\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.datasets.base_dataset:Downloading https://storage.googleapis.com/pyhealth/Synthetic_MIMIC-III/ADMISSIONS.csv to /root/.cache/pyhealth/3b3dd072-c3a0-53d4-90cd-e62cb8e1294a/tmp/5356bbfc-1bfc-45f0-a6f3-691bff93fe5a/ADMISSIONS.csv\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Scanning table: noteevents from https://storage.googleapis.com/pyhealth/Synthetic_MIMIC-III/NOTEEVENTS.csv.gz\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.datasets.base_dataset:Scanning table: noteevents from https://storage.googleapis.com/pyhealth/Synthetic_MIMIC-III/NOTEEVENTS.csv.gz\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Downloading https://storage.googleapis.com/pyhealth/Synthetic_MIMIC-III/NOTEEVENTS.csv to /root/.cache/pyhealth/3b3dd072-c3a0-53d4-90cd-e62cb8e1294a/tmp/d497ae08-d725-4c9e-a556-1f339a6054b6/NOTEEVENTS.csv\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.datasets.base_dataset:Downloading https://storage.googleapis.com/pyhealth/Synthetic_MIMIC-III/NOTEEVENTS.csv to /root/.cache/pyhealth/3b3dd072-c3a0-53d4-90cd-e62cb8e1294a/tmp/d497ae08-d725-4c9e-a556-1f339a6054b6/NOTEEVENTS.csv\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Preprocessing table: noteevents with preprocess_noteevents\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.datasets.base_dataset:Preprocessing table: noteevents with preprocess_noteevents\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Joining with table: https://storage.googleapis.com/pyhealth/Synthetic_MIMIC-III/ADMISSIONS.csv.gz\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.datasets.base_dataset:Joining with table: https://storage.googleapis.com/pyhealth/Synthetic_MIMIC-III/ADMISSIONS.csv.gz\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Downloading https://storage.googleapis.com/pyhealth/Synthetic_MIMIC-III/ADMISSIONS.csv to /root/.cache/pyhealth/3b3dd072-c3a0-53d4-90cd-e62cb8e1294a/tmp/ccb26ae6-3af4-4471-9671-57f3e9549279/ADMISSIONS.csv\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.datasets.base_dataset:Downloading https://storage.googleapis.com/pyhealth/Synthetic_MIMIC-III/ADMISSIONS.csv to /root/.cache/pyhealth/3b3dd072-c3a0-53d4-90cd-e62cb8e1294a/tmp/ccb26ae6-3af4-4471-9671-57f3e9549279/ADMISSIONS.csv\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Caching event dataframe to /root/.cache/pyhealth/3b3dd072-c3a0-53d4-90cd-e62cb8e1294a/global_event_df.parquet...\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.datasets.base_dataset:Caching event dataframe to /root/.cache/pyhealth/3b3dd072-c3a0-53d4-90cd-e62cb8e1294a/global_event_df.parquet...\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Dataset: mimic3\n", + "Dev mode: False\n", + "Number of patients: 49993\n", + "Number of events: 2176707\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "patient1 = dataset.get_patient('1')\n", + "patient1" + ], + "metadata": { + "id": "PgYrkEDEZ2fA", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "b14503b9-dd82-40c9-b818-9bbbd1cf6e17" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Found 49993 unique patient IDs\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.datasets.base_dataset:Found 49993 unique patient IDs\n" + ] + }, + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "" + ] + }, + "metadata": {}, + "execution_count": 4 + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "### **We can get a patient's events by calling the .get_patient() function with their get_events()**\n", + "\n", + "**One key thing to understand is that:**\n", + "\n", + "\n", + "\n", + "1. All events are loaded directly from the tables defined above.\n", + "2. Everything is lazily loaded, meaning no computation is done until data access is required.\n", + "3. The events available are all defined in the .yaml file. **We'll go into the inner-workings of how datasets work later in the deep dive section below.**\n", + "\n", + "\n", + "![Image description](https://drive.google.com/uc?export=view&id=1h3Ija0CqcEBH5ui0upRqRo6Ym1Zt_mTT)\n", + "\n", + "\n" + ], + "metadata": { + "id": "bgRxP_AlPEFl" + } + }, + { + "cell_type": "code", + "source": [ + "dataset.get_patient('1').get_events()" + ], + "metadata": { + "id": "0JEBSOezsDhy", + "collapsed": true, + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "584c8896-0672-4dc5-e773-7819672f50ea" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "[Event(event_type='patients', timestamp=datetime.datetime(2026, 2, 20, 18, 7, 0, 445569), attr_dict={'gender': 'M', 'dob': '2102-09-07', 'dod': None, 'dod_hosp': None, 'dod_ssn': None, 'expire_flag': '0'}),\n", + " Event(event_type='noteevents', timestamp=datetime.datetime(2024, 12, 2, 0, 0), attr_dict={'hadm_id': '100000', 'text': '**Discharge Summary**\\n\\n**Patient Information:**\\n- Name: John Doe\\n- Age: 60\\n- Gender: Male\\n- Medical Record Number: 123456\\n\\n**Admission Details:**\\n- Admit Date: 03/15/2023\\n- Admit Time: 14:30\\n- Discharge Date: 03/22/2023\\n\\n**Chief Complaint:**\\nShortness of breath and mild chest pain after a spinal manipulation therapy session.\\n\\n**History of Present Illness:**\\nPatient Mr. John Doe, a 60-year-old male with a past medical history significant for Type 2 diabetes mellitus, uncontrolled, with background diabetic retinopathy, secondary malignant neoplasm, transplanted kidney, and a history of drug abuse in remission, presented to the ED with acute onset of shortness of breath and mild chest pain. The patient reported feeling pain in his back after undergoing lumbar spinal manipulation therapy earlier in the day. He also noted a mild cough and some difficulty breathing.\\n\\n**Past Medical History:**\\n- Diabetes Mellitus, type II, poorly controlled\\n- Lumbago with previous sprain\\n- Diabetes with retinopathy\\n- History of kidney transplant\\n- Hypoxemia\\n- Secondary malignant neoplasm\\n- Contusion of lung (suggestive of post-procedural complications)\\n- History of drug abuse in remission\\n- Overweight (BMI 28.5)\\n\\n**Pertinent Findings:**\\n- Physical examination revealed normal oxygen saturation at rest and mild tenderness over the lumbar spine.\\n- Chest CT scan showed a contusion of the lung without mention of an open wound into the thorax.\\n- Arterial blood gas (ABG) indicated mild hypoxemia.\\n- EKG and troponin levels were normal.\\n\\n**Hospital Course:**\\nThe patient’s management included supplemental oxygen during hospitalization, continuous monitoring, and rest. Pain relief with NSAIDs and anti-diabetic medication regimen adjusted for better glycemic control. The patient also received education on preventive measures to avoid complications post-spinal manipulation procedures.\\n\\n**Discharge Plan:**\\n1. Continue with follow-up with his primary care physician and endocrinologist for diabetes management.\\n2. Follow-up with the nephrology team for assessment of kidney function post-transplant.\\n3. Avoided high impact activities and to gradually return to normal activities over the next 2-4 weeks under guidance.\\n4. Monitor oxygen saturation levels at rest and with activity.\\n5. Strict adherence to the anti-diabetic medication regimen and avoid spinal manipulation therapies until healed.\\n6. Follow-up with an ophthalmologist for diabetic retinopathy.\\n7. Encourage lifestyle modifications for weight control.\\n\\n**Follow-Up Appointments:**\\nPrimary Care Physician and Endocrinologist in 2 weeks for blood sugar and weight management. Follow-up nephrology evaluation in 4 weeks for kidney function. The next ophthalmology appointment is in 3 months.\\n\\n**Discharge Medications:**\\nMetformin 500mg PO bid, Lisinopril 20mg PO QD, and Oxybutynin 5mg PO TID.\\n\\n---', 'category': 'Discharge summary', 'description': 'Discharge summary', 'storetime': None}),\n", + " Event(event_type='prescriptions', timestamp=datetime.datetime(2103, 6, 7, 0, 0), attr_dict={'hadm_id': '100000', 'drug': 'HYDROmorphone (Dilaudid)', 'drug_type': 'MAIN', 'drug_name_poe': 'HYDROmorphone (Dilaudid)', 'drug_name_generic': 'HYDROmorphone PCA', 'formulary_drug_cd': 'HYD12.5PCA', 'gsn': '004101', 'ndc': '00074233411', 'prod_strength': '12.5mg/50mL Syringe', 'dose_val_rx': '12.5', 'dose_unit_rx': 'mg', 'form_val_disp': '1', 'form_unit_disp': 'SYR', 'route': 'IVPCA', 'enddate': '2103-06-07'}),\n", + " Event(event_type='prescriptions', timestamp=datetime.datetime(2103, 6, 7, 0, 0), attr_dict={'hadm_id': '100000', 'drug': 'Potassium Chloride', 'drug_type': 'MAIN', 'drug_name_poe': None, 'drug_name_generic': None, 'formulary_drug_cd': 'KCL20PM', 'gsn': '045309', 'ndc': '00338070341', 'prod_strength': '20mEq/50ml Premix', 'dose_val_rx': '20', 'dose_unit_rx': 'mEq', 'form_val_disp': '1', 'form_unit_disp': 'BAG', 'route': 'IV', 'enddate': '2103-06-07'}),\n", + " Event(event_type='prescriptions', timestamp=datetime.datetime(2103, 6, 7, 0, 0), attr_dict={'hadm_id': '100000', 'drug': 'Calcium Gluconate', 'drug_type': 'MAIN', 'drug_name_poe': 'Calcium Gluconate', 'drug_name_generic': 'Calcium Gluconate', 'formulary_drug_cd': 'CALG1I', 'gsn': '001356', 'ndc': '00517391025', 'prod_strength': '1g/10mL Vial', 'dose_val_rx': '2', 'dose_unit_rx': 'gm', 'form_val_disp': '2', 'form_unit_disp': 'VIAL', 'route': 'IV', 'enddate': '2103-06-07'}),\n", + " Event(event_type='prescriptions', timestamp=datetime.datetime(2103, 6, 7, 0, 0), attr_dict={'hadm_id': '100000', 'drug': 'Heparin', 'drug_type': 'MAIN', 'drug_name_poe': 'Heparin', 'drug_name_generic': 'Heparin Sodium', 'formulary_drug_cd': 'HEPA5I', 'gsn': '006549', 'ndc': '00641040025', 'prod_strength': '5000U/ML VIAL', 'dose_val_rx': '5000', 'dose_unit_rx': 'UNIT', 'form_val_disp': '1', 'form_unit_disp': 'ml', 'route': 'SC', 'enddate': '2103-06-07'}),\n", + " Event(event_type='prescriptions', timestamp=datetime.datetime(2103, 6, 7, 0, 0), attr_dict={'hadm_id': '100000', 'drug': 'D5W', 'drug_type': 'BASE', 'drug_name_poe': None, 'drug_name_generic': None, 'formulary_drug_cd': 'D5W250', 'gsn': '001972', 'ndc': '00338001702', 'prod_strength': '250ML BAG', 'dose_val_rx': '250', 'dose_unit_rx': 'ml', 'form_val_disp': '250', 'form_unit_disp': 'ml', 'route': 'IV DRIP', 'enddate': '2103-06-07'}),\n", + " Event(event_type='prescriptions', timestamp=datetime.datetime(2103, 6, 7, 0, 0), attr_dict={'hadm_id': '100000', 'drug': 'Pantoprazole Sodium', 'drug_type': 'MAIN', 'drug_name_poe': None, 'drug_name_generic': None, 'formulary_drug_cd': 'PANT40I', 'gsn': '047635', 'ndc': '00008092355', 'prod_strength': '40mg Vial', 'dose_val_rx': '40', 'dose_unit_rx': 'mg', 'form_val_disp': '1', 'form_unit_disp': 'VIAL', 'route': 'IV', 'enddate': '2103-06-07'}),\n", + " Event(event_type='prescriptions', timestamp=datetime.datetime(2103, 6, 7, 0, 0), attr_dict={'hadm_id': '100000', 'drug': 'Acetaminophen', 'drug_type': 'MAIN', 'drug_name_poe': 'Acetaminophen', 'drug_name_generic': 'Acetaminophen', 'formulary_drug_cd': 'ACET325', 'gsn': '004489', 'ndc': '00182844789', 'prod_strength': '325mg Tablet', 'dose_val_rx': '325-650', 'dose_unit_rx': 'mg', 'form_val_disp': '1-2', 'form_unit_disp': 'TAB', 'route': 'PO', 'enddate': '2103-06-07'}),\n", + " Event(event_type='prescriptions', timestamp=datetime.datetime(2103, 6, 7, 0, 0), attr_dict={'hadm_id': '100000', 'drug': 'Docusate Sodium', 'drug_type': 'MAIN', 'drug_name_poe': 'Docusate Sodium', 'drug_name_generic': 'Docusate Sodium', 'formulary_drug_cd': 'DOCU100', 'gsn': '003009', 'ndc': '63739008901', 'prod_strength': '100mg Cap', 'dose_val_rx': '100', 'dose_unit_rx': 'mg', 'form_val_disp': '1', 'form_unit_disp': 'CAP', 'route': 'PO', 'enddate': '2103-06-07'}),\n", + " Event(event_type='prescriptions', timestamp=datetime.datetime(2103, 6, 7, 0, 0), attr_dict={'hadm_id': '100000', 'drug': 'Hydromorphone', 'drug_type': 'MAIN', 'drug_name_poe': 'Hydromorphone', 'drug_name_generic': 'Hydromorphone HCl', 'formulary_drug_cd': 'HYDR2', 'gsn': '004110', 'ndc': '00074241512', 'prod_strength': '2mg Tablet', 'dose_val_rx': '2', 'dose_unit_rx': 'mg', 'form_val_disp': '1', 'form_unit_disp': 'TAB', 'route': 'PO', 'enddate': '2103-06-07'}),\n", + " Event(event_type='prescriptions', timestamp=datetime.datetime(2103, 6, 7, 0, 0), attr_dict={'hadm_id': '100000', 'drug': 'Verapamil', 'drug_type': 'MAIN', 'drug_name_poe': 'Verapamil', 'drug_name_generic': 'Verapamil', 'formulary_drug_cd': 'VERA120', 'gsn': '000564', 'ndc': '51079068320', 'prod_strength': '120 mg Tab', 'dose_val_rx': '240', 'dose_unit_rx': 'mg', 'form_val_disp': '2', 'form_unit_disp': 'TAB', 'route': 'PO', 'enddate': '2103-06-07'}),\n", + " Event(event_type='prescriptions', timestamp=datetime.datetime(2103, 6, 7, 0, 0), attr_dict={'hadm_id': '100000', 'drug': 'Lisinopril', 'drug_type': 'MAIN', 'drug_name_poe': 'Lisinopril', 'drug_name_generic': 'Lisinopril', 'formulary_drug_cd': 'LISI20', 'gsn': '000391', 'ndc': '00310013239', 'prod_strength': '20MG TAB', 'dose_val_rx': '40', 'dose_unit_rx': 'mg', 'form_val_disp': '2', 'form_unit_disp': 'TAB', 'route': 'PO', 'enddate': '2103-06-07'}),\n", + " Event(event_type='prescriptions', timestamp=datetime.datetime(2103, 6, 7, 0, 0), attr_dict={'hadm_id': '100000', 'drug': 'Amoxicillin-Clavulanic Acid', 'drug_type': 'MAIN', 'drug_name_poe': 'Amoxicillin-Clavulanic Acid', 'drug_name_generic': 'Amoxicillin-Clavulanic Acid', 'formulary_drug_cd': 'AUGM500', 'gsn': '008992', 'ndc': '00029608031', 'prod_strength': '500mg Tab', 'dose_val_rx': '500', 'dose_unit_rx': 'mg', 'form_val_disp': '1', 'form_unit_disp': 'TAB', 'route': 'PO', 'enddate': '2103-06-07'}),\n", + " Event(event_type='prescriptions', timestamp=datetime.datetime(2103, 6, 7, 0, 0), attr_dict={'hadm_id': '100000', 'drug': 'Sertraline', 'drug_type': 'MAIN', 'drug_name_poe': 'Sertraline', 'drug_name_generic': 'Sertraline', 'formulary_drug_cd': 'SERT50', 'gsn': '046228', 'ndc': '52959036100', 'prod_strength': '50mg Tablet', 'dose_val_rx': '50', 'dose_unit_rx': 'mg', 'form_val_disp': '1', 'form_unit_disp': 'TAB', 'route': 'PO', 'enddate': '2103-06-07'}),\n", + " Event(event_type='prescriptions', timestamp=datetime.datetime(2103, 6, 7, 0, 0), attr_dict={'hadm_id': '100000', 'drug': 'Milk of Magnesia', 'drug_type': 'MAIN', 'drug_name_poe': 'Milk of Magnesia', 'drug_name_generic': 'Milk Of Magnesia', 'formulary_drug_cd': 'MOM30L', 'gsn': '003026', 'ndc': '66689036430', 'prod_strength': '30mL UD Cup', 'dose_val_rx': '30', 'dose_unit_rx': 'ml', 'form_val_disp': '1', 'form_unit_disp': 'UDCUP', 'route': 'PO', 'enddate': '2103-06-07'}),\n", + " Event(event_type='prescriptions', timestamp=datetime.datetime(2103, 6, 7, 0, 0), attr_dict={'hadm_id': '100000', 'drug': 'Nicotine Patch', 'drug_type': 'MAIN', 'drug_name_poe': 'Nicotine Patch', 'drug_name_generic': 'Nicotine Patch', 'formulary_drug_cd': 'NICO21P', 'gsn': '016427', 'ndc': '00766145010', 'prod_strength': '21mg/24Hr Patch', 'dose_val_rx': '21', 'dose_unit_rx': 'mg', 'form_val_disp': '1', 'form_unit_disp': 'PTCH', 'route': 'TD', 'enddate': '2103-06-07'}),\n", + " Event(event_type='prescriptions', timestamp=datetime.datetime(2103, 6, 7, 0, 0), attr_dict={'hadm_id': '100000', 'drug': 'Haloperidol', 'drug_type': 'MAIN', 'drug_name_poe': 'Haloperidol', 'drug_name_generic': 'Haloperidol', 'formulary_drug_cd': 'HALD5I', 'gsn': '003968', 'ndc': '00045025501', 'prod_strength': '5mg/mL Vial', 'dose_val_rx': '1-5', 'dose_unit_rx': 'mg', 'form_val_disp': '0.2-1', 'form_unit_disp': 'VIAL', 'route': 'IV', 'enddate': '2103-06-07'}),\n", + " Event(event_type='prescriptions', timestamp=datetime.datetime(2103, 6, 7, 0, 0), attr_dict={'hadm_id': '100000', 'drug': 'Ceftriaxone', 'drug_type': 'MAIN', 'drug_name_poe': None, 'drug_name_generic': None, 'formulary_drug_cd': 'CEFX1F', 'gsn': '009156', 'ndc': '00004200278', 'prod_strength': '1GM FROZ BAG', 'dose_val_rx': '1', 'dose_unit_rx': 'gm', 'form_val_disp': '1', 'form_unit_disp': 'BAG', 'route': 'IV', 'enddate': '2103-06-07'}),\n", + " Event(event_type='prescriptions', timestamp=datetime.datetime(2103, 6, 7, 0, 0), attr_dict={'hadm_id': '100000', 'drug': 'Oxycodone-Acetaminophen', 'drug_type': 'MAIN', 'drug_name_poe': 'Oxycodone-Acetaminophen', 'drug_name_generic': 'Oxycodone-Acetaminophen', 'formulary_drug_cd': 'PERC', 'gsn': '004222', 'ndc': '00406051201', 'prod_strength': '5mg/325mg Tablet', 'dose_val_rx': '1-2', 'dose_unit_rx': 'TAB', 'form_val_disp': '1-2', 'form_unit_disp': 'TAB', 'route': 'PO', 'enddate': '2103-06-07'}),\n", + " Event(event_type='prescriptions', timestamp=datetime.datetime(2103, 6, 7, 0, 0), attr_dict={'hadm_id': '100000', 'drug': 'Pneumococcal Vac Polyvalent', 'drug_type': 'MAIN', 'drug_name_poe': 'Pneumococcal Vac Polyvalent', 'drug_name_generic': 'Pneumococcal Vac Polyvalent', 'formulary_drug_cd': 'PNEU25I', 'gsn': '048548', 'ndc': '00006494300', 'prod_strength': '25mcg/0.5mL Vial', 'dose_val_rx': '0.5', 'dose_unit_rx': 'ml', 'form_val_disp': '1', 'form_unit_disp': 'VIAL', 'route': 'IM', 'enddate': '2103-06-07'}),\n", + " Event(event_type='prescriptions', timestamp=datetime.datetime(2103, 6, 7, 0, 0), attr_dict={'hadm_id': '100000', 'drug': 'Ranitidine', 'drug_type': 'MAIN', 'drug_name_poe': 'Ranitidine', 'drug_name_generic': 'Ranitidine HCl', 'formulary_drug_cd': 'RANI150', 'gsn': '011673', 'ndc': '00904526161', 'prod_strength': '150mg Tablet', 'dose_val_rx': '150', 'dose_unit_rx': 'mg', 'form_val_disp': '1', 'form_unit_disp': 'TAB', 'route': 'PO', 'enddate': '2103-06-07'}),\n", + " Event(event_type='prescriptions', timestamp=datetime.datetime(2103, 6, 7, 0, 0), attr_dict={'hadm_id': '100000', 'drug': 'Hydromorphone', 'drug_type': 'MAIN', 'drug_name_poe': 'Hydromorphone', 'drug_name_generic': 'Hydromorphone', 'formulary_drug_cd': 'HYDR2I', 'gsn': '004103', 'ndc': '00074131230', 'prod_strength': '2mg/mL Syringe', 'dose_val_rx': '0.5-1', 'dose_unit_rx': 'mg', 'form_val_disp': '0.25-0.5', 'form_unit_disp': 'SYR', 'route': 'SC', 'enddate': '2103-06-07'}),\n", + " Event(event_type='prescriptions', timestamp=datetime.datetime(2103, 6, 7, 0, 0), attr_dict={'hadm_id': '100000', 'drug': 'NIFEdipine CR', 'drug_type': 'MAIN', 'drug_name_poe': 'NIFEdipine CR', 'drug_name_generic': 'NIFEdipine CR', 'formulary_drug_cd': 'ADAL90', 'gsn': '012061', 'ndc': '00085172202', 'prod_strength': '90 mg CR Tab', 'dose_val_rx': '90', 'dose_unit_rx': 'mg', 'form_val_disp': '1', 'form_unit_disp': 'TAB', 'route': 'PO', 'enddate': '2103-06-07'}),\n", + " Event(event_type='prescriptions', timestamp=datetime.datetime(2103, 6, 7, 0, 0), attr_dict={'hadm_id': '100000', 'drug': 'Hydralazine HCl', 'drug_type': 'MAIN', 'drug_name_poe': 'Hydralazine HCl', 'drug_name_generic': 'Hydralazine HCl', 'formulary_drug_cd': 'HYDZ20I', 'gsn': '000283', 'ndc': '00517090125', 'prod_strength': '20mg/mL Vial', 'dose_val_rx': '10', 'dose_unit_rx': 'mg', 'form_val_disp': '0.5', 'form_unit_disp': 'VIAL', 'route': 'IV', 'enddate': '2103-06-07'}),\n", + " Event(event_type='icustays', timestamp=datetime.datetime(2103, 6, 7, 0, 0), attr_dict={'icustay_id': '200000', 'first_careunit': 'SICU', 'dbsource': 'carevue', 'last_careunit': 'SICU', 'outtime': '2103-06-07'}),\n", + " Event(event_type='procedures_icd', timestamp=datetime.datetime(2103, 6, 7, 12, 0), attr_dict={'hadm_id': '100000', 'icd9_code': '8472', 'seq_num': '3'}),\n", + " Event(event_type='procedures_icd', timestamp=datetime.datetime(2103, 6, 7, 12, 0), attr_dict={'hadm_id': '100000', 'icd9_code': '544', 'seq_num': '1'}),\n", + " Event(event_type='procedures_icd', timestamp=datetime.datetime(2103, 6, 7, 12, 0), attr_dict={'hadm_id': '100000', 'icd9_code': '3895', 'seq_num': '0'}),\n", + " Event(event_type='diagnoses_icd', timestamp=datetime.datetime(2103, 6, 7, 12, 0), attr_dict={'hadm_id': '100000', 'icd9_code': '86121', 'seq_num': '0'}),\n", + " Event(event_type='diagnoses_icd', timestamp=datetime.datetime(2103, 6, 7, 12, 0), attr_dict={'hadm_id': '100000', 'icd9_code': 'V4589', 'seq_num': '1'}),\n", + " Event(event_type='diagnoses_icd', timestamp=datetime.datetime(2103, 6, 7, 12, 0), attr_dict={'hadm_id': '100000', 'icd9_code': '25082', 'seq_num': '2'}),\n", + " Event(event_type='diagnoses_icd', timestamp=datetime.datetime(2103, 6, 7, 12, 0), attr_dict={'hadm_id': '100000', 'icd9_code': '79902', 'seq_num': '3'}),\n", + " Event(event_type='procedures_icd', timestamp=datetime.datetime(2103, 6, 7, 12, 0), attr_dict={'hadm_id': '100000', 'icd9_code': '9618', 'seq_num': '2'}),\n", + " Event(event_type='diagnoses_icd', timestamp=datetime.datetime(2103, 6, 7, 12, 0), attr_dict={'hadm_id': '100000', 'icd9_code': '19889', 'seq_num': '4'}),\n", + " Event(event_type='admissions', timestamp=datetime.datetime(2103, 6, 7, 12, 0), attr_dict={'hadm_id': '100000', 'admission_type': 'EMERGENCY', 'admission_location': 'EMERGENCY ROOM ADMIT', 'insurance': 'Private', 'language': None, 'religion': 'CATHOLIC', 'marital_status': None, 'ethnicity': 'UNABLE TO OBTAIN', 'edregtime': None, 'edouttime': None, 'diagnosis': None, 'discharge_location': 'HOME HEALTH CARE', 'dischtime': '2103-06-07 12:00:00', 'hospital_expire_flag': '0'}),\n", + " Event(event_type='diagnoses_icd', timestamp=datetime.datetime(2103, 6, 7, 12, 0), attr_dict={'hadm_id': '100000', 'icd9_code': '36201', 'seq_num': '5'}),\n", + " Event(event_type='diagnoses_icd', timestamp=datetime.datetime(2103, 6, 7, 12, 0), attr_dict={'hadm_id': '100000', 'icd9_code': '27802', 'seq_num': '7'}),\n", + " Event(event_type='diagnoses_icd', timestamp=datetime.datetime(2103, 6, 7, 12, 0), attr_dict={'hadm_id': '100000', 'icd9_code': '99681', 'seq_num': '6'}),\n", + " Event(event_type='diagnoses_icd', timestamp=datetime.datetime(2103, 6, 7, 12, 0), attr_dict={'hadm_id': '100000', 'icd9_code': '30593', 'seq_num': '8'})]" + ] + }, + "metadata": {}, + "execution_count": 5 + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "### If you want to iterate across each patient's events, you can do something like below\n", + "\n" + ], + "metadata": { + "id": "HkcNx2BohaAX" + } + }, + { + "cell_type": "code", + "source": [ + "patient_ids = dataset.unique_patient_ids\n", + "for patient_id in patient_ids[:2]: # Iterate through the first 2 patient IDs\n", + " patient = dataset.get_patient(patient_id)\n", + " print(f\"Patient ID: {patient_id}\")\n", + " for i, event in enumerate(patient.get_events()):\n", + " if i < 2: # Print only the first 2 events for each patient\n", + " print(event)\n", + " else:\n", + " break # Stop iterating through events after printing 2" + ], + "metadata": { + "id": "wfvGSEnkiU0j", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "d6cae20d-5b0d-4543-f1d8-68f5abbecd9f" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Patient ID: 17900\n", + "Event(event_type='patients', timestamp=datetime.datetime(2026, 2, 20, 18, 7, 0, 461446), attr_dict={'gender': 'M', 'dob': '2125-04-11', 'dod': None, 'dod_hosp': None, 'dod_ssn': None, 'expire_flag': '0'})\n", + "Event(event_type='prescriptions', timestamp=datetime.datetime(2125, 6, 22, 0, 0), attr_dict={'hadm_id': '118575', 'drug': 'Gentamicin', 'drug_type': 'MAIN', 'drug_name_poe': None, 'drug_name_generic': None, 'formulary_drug_cd': 'GENT80PM', 'gsn': '009291', 'ndc': '00338050941', 'prod_strength': '80mg Premix', 'dose_val_rx': '80', 'dose_unit_rx': 'mg', 'form_val_disp': '1', 'form_unit_disp': 'BAG', 'route': 'IV', 'enddate': '2125-06-23'})\n", + "Patient ID: 23726\n", + "Event(event_type='patients', timestamp=datetime.datetime(2026, 2, 20, 18, 7, 0, 472646), attr_dict={'gender': 'F', 'dob': '1976-07-10', 'dod': '1976-11-10', 'dod_hosp': '1976-11-10', 'dod_ssn': '1976-11-10', 'expire_flag': '1'})\n", + "Event(event_type='icustays', timestamp=datetime.datetime(1976, 11, 10, 0, 0), attr_dict={'icustay_id': '224634', 'first_careunit': 'SICU', 'dbsource': 'carevue', 'last_careunit': 'SICU', 'outtime': '1976-11-10'})\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "### Let us do some explorations with the events\n", + "\n" + ], + "metadata": { + "id": "6OgF6H_Jrz0S" + } + }, + { + "cell_type": "code", + "source": [ + "# get patient dictionary\n", + "icd_events = dataset.get_patient('1').get_events(\"diagnoses_icd\")\n", + "print(icd_events)\n", + "for icd_event in icd_events:\n", + " print(icd_event.icd9_code)" + ], + "metadata": { + "id": "gZP5AHAfr5y4", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "673f4693-adb6-4210-ad2b-5198bb055307" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "[Event(event_type='diagnoses_icd', timestamp=datetime.datetime(2103, 6, 7, 12, 0), attr_dict={'hadm_id': '100000', 'icd9_code': '86121', 'seq_num': '0'}), Event(event_type='diagnoses_icd', timestamp=datetime.datetime(2103, 6, 7, 12, 0), attr_dict={'hadm_id': '100000', 'icd9_code': 'V4589', 'seq_num': '1'}), Event(event_type='diagnoses_icd', timestamp=datetime.datetime(2103, 6, 7, 12, 0), attr_dict={'hadm_id': '100000', 'icd9_code': '25082', 'seq_num': '2'}), Event(event_type='diagnoses_icd', timestamp=datetime.datetime(2103, 6, 7, 12, 0), attr_dict={'hadm_id': '100000', 'icd9_code': '79902', 'seq_num': '3'}), Event(event_type='diagnoses_icd', timestamp=datetime.datetime(2103, 6, 7, 12, 0), attr_dict={'hadm_id': '100000', 'icd9_code': '19889', 'seq_num': '4'}), Event(event_type='diagnoses_icd', timestamp=datetime.datetime(2103, 6, 7, 12, 0), attr_dict={'hadm_id': '100000', 'icd9_code': '36201', 'seq_num': '5'}), Event(event_type='diagnoses_icd', timestamp=datetime.datetime(2103, 6, 7, 12, 0), attr_dict={'hadm_id': '100000', 'icd9_code': '27802', 'seq_num': '7'}), Event(event_type='diagnoses_icd', timestamp=datetime.datetime(2103, 6, 7, 12, 0), attr_dict={'hadm_id': '100000', 'icd9_code': '99681', 'seq_num': '6'}), Event(event_type='diagnoses_icd', timestamp=datetime.datetime(2103, 6, 7, 12, 0), attr_dict={'hadm_id': '100000', 'icd9_code': '30593', 'seq_num': '8'})]\n", + "86121\n", + "V4589\n", + "25082\n", + "79902\n", + "19889\n", + "36201\n", + "27802\n", + "99681\n", + "30593\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "# get patient dictionary\n", + "icd_events = dataset.get_patient('1').get_events(\"procedures_icd\")\n", + "print(icd_events)\n", + "for icd_event in icd_events:\n", + " print(icd_event.icd9_code)" + ], + "metadata": { + "id": "sv7sR4qn0oLY", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "4d3c8fca-9599-4619-ecd2-d055bb1e8130" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "[Event(event_type='procedures_icd', timestamp=datetime.datetime(2103, 6, 7, 12, 0), attr_dict={'hadm_id': '100000', 'icd9_code': '8472', 'seq_num': '3'}), Event(event_type='procedures_icd', timestamp=datetime.datetime(2103, 6, 7, 12, 0), attr_dict={'hadm_id': '100000', 'icd9_code': '544', 'seq_num': '1'}), Event(event_type='procedures_icd', timestamp=datetime.datetime(2103, 6, 7, 12, 0), attr_dict={'hadm_id': '100000', 'icd9_code': '3895', 'seq_num': '0'}), Event(event_type='procedures_icd', timestamp=datetime.datetime(2103, 6, 7, 12, 0), attr_dict={'hadm_id': '100000', 'icd9_code': '9618', 'seq_num': '2'})]\n", + "8472\n", + "544\n", + "3895\n", + "9618\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "**And, if we wanted to pick an event at specific interval (i.e a hospital visit/admission), we can:**" + ], + "metadata": { + "id": "U3pGdWfdlKNr" + } + }, + { + "cell_type": "code", + "source": [ + "admissions = dataset.get_patient('1').get_events(\"admissions\")\n", + "start = admissions[0].timestamp\n", + "procedures = dataset.get_patient('1').get_events(\"procedures_icd\", start=start)\n", + "print(procedures)\n" + ], + "metadata": { + "id": "zL0y8q6clJuc", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "a8621ab1-942a-484a-dcf9-918ed4db9965" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "[Event(event_type='procedures_icd', timestamp=datetime.datetime(2103, 6, 7, 12, 0), attr_dict={'hadm_id': '100000', 'icd9_code': '8472', 'seq_num': '3'}), Event(event_type='procedures_icd', timestamp=datetime.datetime(2103, 6, 7, 12, 0), attr_dict={'hadm_id': '100000', 'icd9_code': '544', 'seq_num': '1'}), Event(event_type='procedures_icd', timestamp=datetime.datetime(2103, 6, 7, 12, 0), attr_dict={'hadm_id': '100000', 'icd9_code': '3895', 'seq_num': '0'}), Event(event_type='procedures_icd', timestamp=datetime.datetime(2103, 6, 7, 12, 0), attr_dict={'hadm_id': '100000', 'icd9_code': '9618', 'seq_num': '2'})]\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "## **Going Deeper: What event types and attributes are available?**\n", + "\n", + "Below, we showcase an example of our config YAML files that pre-define what is pre-loaded for use in MIMIC3. For a full look of the config file as well as where this is located in PyHealth, see [here](https://github.com/sunlabuiuc/PyHealth/blob/master/pyhealth/datasets/configs/mimic3.yaml). For brevity's sake, we showcase the tables we used above below:\n", + "\n" + ], + "metadata": { + "id": "pv9VUbg8zeV0" + } + }, + { + "cell_type": "markdown", + "source": [ + "\n", + "\n", + "```\n", + "version: \"1.4\"\n", + "tables:\n", + " patients:\n", + " file_path: \"PATIENTS.csv.gz\"\n", + " patient_id: \"subject_id\"\n", + " timestamp: null\n", + " attributes:\n", + " - \"gender\"\n", + " - \"dob\"\n", + " - \"dod\"\n", + " - \"dod_hosp\"\n", + " - \"dod_ssn\"\n", + " - \"expire_flag\"\n", + "\n", + " admissions:\n", + " file_path: \"ADMISSIONS.csv.gz\"\n", + " patient_id: \"subject_id\"\n", + " timestamp: \"admittime\"\n", + " attributes:\n", + " - \"hadm_id\"\n", + " - \"admission_type\"\n", + " - \"admission_location\"\n", + " - \"insurance\"\n", + " - \"language\"\n", + " - \"religion\"\n", + " - \"marital_status\"\n", + " - \"ethnicity\"\n", + " - \"edregtime\"\n", + " - \"edouttime\"\n", + " - \"diagnosis\"\n", + " - \"discharge_location\"\n", + " - \"dischtime\"\n", + " - \"hospital_expire_flag\"\n", + "\n", + " diagnoses_icd:\n", + " file_path: \"DIAGNOSES_ICD.csv.gz\"\n", + " patient_id: \"subject_id\"\n", + " join:\n", + " - file_path: \"ADMISSIONS.csv.gz\"\n", + " \"on\": \"hadm_id\"\n", + " how: \"inner\"\n", + " columns:\n", + " - \"dischtime\"\n", + " timestamp: \"dischtime\"\n", + " attributes:\n", + " - \"icd9_code\"\n", + " - \"seq_num\"\n", + "\n", + " procedures_icd:\n", + " file_path: \"PROCEDURES_ICD.csv.gz\"\n", + " patient_id: \"subject_id\"\n", + " join:\n", + " - file_path: \"ADMISSIONS.csv.gz\"\n", + " \"on\": \"hadm_id\"\n", + " how: \"inner\"\n", + " columns:\n", + " - \"dischtime\"\n", + " timestamp: \"dischtime\"\n", + " attributes:\n", + " - \"icd9_code\"\n", + " - \"seq_num\"\n", + "\n", + "```\n", + "\n" + ], + "metadata": { + "id": "1oWUKr_HqKkY" + } + }, + { + "cell_type": "markdown", + "source": [ + "One key thing you'll notice is the name of the **tables** that are available in the loading of our dataset. In this case, **\"diagnoses_icd\"** and **\"procedures_icd\"** are defined with the following required definitions in the YAML file above:\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "* **patient_id**, uses to define which column \"subject_id\" that represents the identifier for the patient_ids. Effectively, this defines what a \"sample\" is in our dataset. Left null, it indicates that every row in each \"table\" (file.csv, etc.) is a sample in our dataframe.\n", + "\n", + "* **file_path**, defines what file in the **root* directory that should be read by PyHealth's polar backend to load the data from.\n", + "\n", + "* **timestamp**, defines what table column to look at for time parsing\n", + "\n", + "* **attributes**, defines what columns to read for each row to store in our Event data structure. In this case, for each table, we can see we have **icd9_code** that we explored above.\n", + "\n", + "* **join**, we can also optionally define joins if we want to merge tables into the main **ADMISSIONS** tables based on their hospital admissions id **hadm_id** for task-specific purposes (i.e mortality prediction/readmission prediction/etc. We discuss more of this in a later tutorial)." + ], + "metadata": { + "id": "NSrb2PGFqUgS" + } + }, + { + "cell_type": "markdown", + "source": [ + "## **Contributing your own dataset**\n", + "We go over how to define your own datasets below. There are essentially 2 steps:\n", + "\n", + "\n", + "1. Defining your dataset_config.yaml file.\n", + "2. Defining your dataset_interface.py\n", + "\n", + "We go over two implementation examples to showcase how to implement **2 types of datasets.**\n", + "\n", + "1. Datasets that are already in a table (i.e MIMIC-III)\n", + "2. Datasets that are in a file directory format (i.e Covid19CXR)\n" + ], + "metadata": { + "id": "YIWZqJrHxFQw" + } + }, + { + "cell_type": "markdown", + "source": [ + "### **Example 1 - MIMIC3**\n", + "\n", + "#### **1. Defining mimic3.yaml**\n", + "\n", + "Every configuration file is defined in **pyhealth/datasets/configs** [here](https://github.com/sunlabuiuc/PyHealth/tree/master/pyhealth/datasets/configs).\n", + "\n", + "Simply create a .yaml file, and define the **tables** that are available like the following:\n", + "\n", + "\n", + "\n", + "```\n", + "version: \"1.4\"\n", + "tables:\n", + " patients:\n", + " file_path: \"PATIENTS.csv.gz\"\n", + " patient_id: \"subject_id\"\n", + " timestamp: null\n", + " attributes:\n", + " - \"gender\"\n", + " - \"dob\"\n", + " - \"dod\"\n", + " - \"dod_hosp\"\n", + " - \"dod_ssn\"\n", + " - \"expire_flag\"\n", + "```\n", + "The PyHealth BaseDataset class will automatically read these tables in with these defined attributes.\n", + "\n" + ], + "metadata": { + "id": "j-CDPfq_6H1m" + } + }, + { + "cell_type": "markdown", + "source": [ + "#### **2. Defining MIMIC3Dataset**\n", + "Once your config.yaml file is defined, we will need to define a class that inherits **BaseDataset**, which does much of the processing underneath the hood. For the ugly details, see [here](https://github.com/sunlabuiuc/PyHealth/blob/master/pyhealth/datasets/base_dataset.py).\n", + "\n" + ], + "metadata": { + "id": "aNvjwQu48ftW" + } + }, + { + "cell_type": "code", + "source": [ + "import logging\n", + "import warnings\n", + "from pathlib import Path\n", + "from typing import List, Optional\n", + "\n", + "import polars as pl\n", + "\n", + "from pyhealth.datasets.base_dataset import BaseDataset\n", + "\n", + "logger = logging.getLogger(__name__)\n", + "\n", + "\n", + "class MIMIC3Dataset(BaseDataset):\n", + " \"\"\"\n", + " A dataset class for handling MIMIC-III data.\n", + "\n", + " This class is responsible for loading and managing the MIMIC-III dataset,\n", + " which includes tables such as patients, admissions, and icustays.\n", + "\n", + " Attributes:\n", + " root (str): The root directory where the dataset is stored.\n", + " tables (List[str]): A list of tables to be included in the dataset.\n", + " dataset_name (Optional[str]): The name of the dataset.\n", + " config_path (Optional[str]): The path to the configuration file.\n", + " \"\"\"\n", + "\n", + " def __init__(\n", + " self,\n", + " root: str,\n", + " tables: List[str],\n", + " dataset_name: Optional[str] = None,\n", + " config_path: Optional[str] = None,\n", + " **kwargs\n", + " ) -> None:\n", + " \"\"\"\n", + " Initializes the MIMIC4Dataset with the specified parameters.\n", + "\n", + " Args:\n", + " root (str): The root directory where the dataset is stored.\n", + " tables (List[str]): A list of additional tables to include.\n", + " dataset_name (Optional[str]): The name of the dataset. Defaults to \"mimic3\".\n", + " config_path (Optional[str]): The path to the configuration file. If not provided, a default config is used.\n", + " \"\"\"\n", + " if config_path is None:\n", + " logger.info(\"No config path provided, using default config\")\n", + " config_path = Path(__file__).parent / \"configs\" / \"mimic3.yaml\"\n", + " default_tables = [\"patients\", \"admissions\", \"icustays\"]\n", + " tables = default_tables + tables\n", + " if \"prescriptions\" in tables:\n", + " warnings.warn(\n", + " \"Events from prescriptions table only have date timestamp (no specific time). \"\n", + " \"This may affect temporal ordering of events.\",\n", + " UserWarning,\n", + " )\n", + " super().__init__(\n", + " root=root,\n", + " tables=tables,\n", + " dataset_name=dataset_name or \"mimic3\",\n", + " config_path=config_path,\n", + " **kwargs\n", + " )\n", + " return\n", + "\n", + " def preprocess_noteevents(self, df: pl.LazyFrame) -> pl.LazyFrame:\n", + " \"\"\"\n", + " Table-specific preprocess function which will be called by BaseDataset.load_table().\n", + "\n", + " Preprocesses the noteevents table by ensuring that the charttime column\n", + " is populated. If charttime is null, it uses chartdate with a default\n", + " time of 00:00:00.\n", + "\n", + " See: https://mimic.mit.edu/docs/iii/tables/noteevents/#chartdate-charttime-storetime.\n", + "\n", + " Args:\n", + " df (pl.LazyFrame): The input dataframe containing noteevents data.\n", + "\n", + " Returns:\n", + " pl.LazyFrame: The processed dataframe with updated charttime\n", + " values.\n", + " \"\"\"\n", + " df = df.with_columns(\n", + " pl.when(pl.col(\"charttime\").is_null())\n", + " .then(pl.col(\"chartdate\") + pl.lit(\" 00:00:00\"))\n", + " .otherwise(pl.col(\"charttime\"))\n", + " .alias(\"charttime\")\n", + " )\n", + " return df" + ], + "metadata": { + "id": "UZbKvKHF8PxW" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "#### **Code Breakdown**\n", + "It looks scary at first, but let's break it down, we can first specify a default config path that **BaseDataset** will use to load tables:\n", + "\n", + "```\n", + "if config_path is None:\n", + " logger.info(\"No config path provided, using default config\")\n", + " config_path = Path(__file__).parent / \"configs\" / \"mimic3.yaml\"\n", + "```\n", + "Next, we define some defualt tables that are always parsed for the dataset, regardless of the user's arguments. **This is key for datasets where there is one metadata table that unifies all other tables like it is in MIMIC-III.** We also offer some warnings about dataset specifics for those who have never used the prescriptions table before.\n", + "\n", + "\n", + "```\n", + "default_tables = [\"patients\", \"admissions\", \"icustays\"]\n", + " tables = default_tables + tables\n", + " if \"prescriptions\" in tables:\n", + " warnings.warn(\n", + " \"Events from prescriptions table only have date timestamp (no specific time). \"\n", + " \"This may affect temporal ordering of events.\",\n", + " UserWarning,\n", + " )\n", + "```\n", + "\n", + "Finally, **we make sure to run the optimized BaseDataset:** that will do the heavy lifting behind the scenes.\n", + "\n", + "```\n", + "super().__init__(\n", + " root=root,\n", + " tables=tables,\n", + " dataset_name=dataset_name or \"mimic3\",\n", + " config_path=config_path,\n", + " **kwargs\n", + " )\n", + " return\n", + "```\n", + "\n", + "\n", + "**You'll also see we offer overrides for how tables are processed in BaseDataset:**\n", + "\n", + "```\n", + "def preprocess_noteevents(self, df: pl.LazyFrame) -> pl.LazyFrame:\n", + " \"\"\"\n", + " Table-specific preprocess function which will be called by BaseDataset.load_table().\n", + " \n", + " Preprocesses the noteevents table by ensuring that the charttime column\n", + " is populated. If charttime is null, it uses chartdate with a default\n", + " time of 00:00:00.\n", + "\n", + " See: https://mimic.mit.edu/docs/iii/tables/noteevents/#chartdate-charttime-storetime.\n", + "\n", + " Args:\n", + " df (pl.LazyFrame): The input dataframe containing noteevents data.\n", + "\n", + " Returns:\n", + " pl.LazyFrame: The processed dataframe with updated charttime\n", + " values.\n", + " \"\"\"\n", + " df = df.with_columns(\n", + " pl.when(pl.col(\"charttime\").is_null())\n", + " .then(pl.col(\"chartdate\") + pl.lit(\" 00:00:00\"))\n", + " .otherwise(pl.col(\"charttime\"))\n", + " .alias(\"charttime\")\n", + " )\n", + " return df\n", + "```\n", + "\n", + "BaseDataset will override how it reads any **table** if you define your own **preprocess_{table}** functions within the class. Here, it adjusts for how dates are represented in the noteevents table, which is different than the usual discharge date columns within the other tables.\n", + "\n", + "\n", + "\n" + ], + "metadata": { + "id": "-Dmt5EFP8TxC" + } + }, + { + "cell_type": "markdown", + "source": [ + "### **Example 2. COVID-CXR Dataset**\n", + "Here, the data is not formatted as a table, so you might be confused on how to contribute a dataset.\n", + "\n", + "**If none of the data is defined in a tabular format, we can simply construct a table such that it can leverage all of the tricks implemented by BaseDataset.**\n", + "\n", + "Let's first start by defining our dataset implementation, located [here](https://github.com/sunlabuiuc/PyHealth/blob/master/pyhealth/datasets/covid19_cxr.py).\n", + "\n", + "#### **1. Defining COVID19CXRDataset**" + ], + "metadata": { + "id": "QQHtI7tcANj4" + } + }, + { + "cell_type": "code", + "source": [ + "import logging\n", + "import os\n", + "from pathlib import Path\n", + "from typing import Optional\n", + "\n", + "import pandas as pd\n", + "\n", + "from pyhealth.tasks import COVID19CXRClassification\n", + "from pyhealth.datasets.base_dataset import BaseDataset\n", + "\n", + "logger = logging.getLogger(__name__)\n", + "\n", + "\n", + "class COVID19CXRDataset(BaseDataset):\n", + " \"\"\"Base image dataset for COVID-19 Radiography Database.\n", + "\n", + " Dataset is available at:\n", + " https://www.kaggle.com/datasets/tawsifurrahman/covid19-radiography-database\n", + "\n", + " Data Sources:\n", + " ------------\n", + " COVID-19 data:\n", + " - 2473 CXR images from padchest dataset[1]\n", + " - 183 CXR images from a Germany medical school[2]\n", + " - 559 CXR images from SIRM, Github, Kaggle & Tweeter[3,4,5,6]\n", + " - 400 CXR images from another Github source[7]\n", + "\n", + " Normal images:\n", + " - 8851 from RSNA [8]\n", + " - 1341 from Kaggle [9]\n", + "\n", + " Lung opacity images:\n", + " - 6012 from Radiological Society of North America (RSNA) CXR dataset[8]\n", + "\n", + " Viral Pneumonia images:\n", + " - 1345 from the Chest X-Ray Images (pneumonia) database[9]\n", + "\n", + " Citations:\n", + " ---------\n", + " If you use this dataset, please cite:\n", + " 1. M.E.H. Chowdhury, T. Rahman, A. Khandakar, et al. \"Can AI help in\n", + " screening Viral and COVID-19 pneumonia?\" IEEE Access, Vol. 8, 2020,\n", + " pp. 132665-132676.\n", + " 2. Rahman, T., Khandakar, A., Qiblawey, Y., et al. \"Exploring the Effect\n", + " of Image Enhancement Techniques on COVID-19 Detection using Chest X-ray\n", + " Images.\" arXiv preprint arXiv:2012.02238.\n", + "\n", + " References:\n", + " ----------\n", + " [1] https://bimcv.cipf.es/bimcv-projects/bimcv-covid19/\n", + " [2] https://github.com/ml-workgroup/covid-19-image-repository/tree/master/png\n", + " [3] https://sirm.org/category/senza-categoria/covid-19/\n", + " [4] https://eurorad.org\n", + " [5] https://github.com/ieee8023/covid-chestxray-dataset\n", + " [6] https://figshare.com/articles/COVID-19_Chest_X-Ray_Image_Repository/12580328\n", + " [7] https://github.com/armiro/COVID-CXNet\n", + " [8] https://www.kaggle.com/c/rsna-pneumonia-detection-challenge/data\n", + " [9] https://www.kaggle.com/paultimothymooney/chest-xray-pneumonia\n", + "\n", + " Args:\n", + " root: Root directory of the raw data containing the dataset files.\n", + " dataset_name: Optional name of the dataset. Defaults to \"covid19_cxr\".\n", + " config_path: Optional path to the configuration file. If not provided,\n", + " uses the default config in the configs directory.\n", + "\n", + " Attributes:\n", + " root: Root directory of the raw data.\n", + " dataset_name: Name of the dataset.\n", + " config_path: Path to the configuration file.\n", + "\n", + " Examples:\n", + " >>> from pyhealth.datasets import COVID19CXRDataset\n", + " >>> dataset = COVID19CXRDataset(\n", + " ... root=\"/path/to/covid19_cxr\"\n", + " ... )\n", + " >>> dataset.stats()\n", + " >>> samples = dataset.set_task()\n", + " >>> print(samples[0])\n", + " \"\"\"\n", + "\n", + " def __init__(\n", + " self,\n", + " root: str,\n", + " dataset_name: Optional[str] = None,\n", + " config_path: Optional[str] = None,\n", + " ) -> None:\n", + " if config_path is None:\n", + " logger.info(\"No config path provided, using default config\")\n", + " config_path = (\n", + " Path(__file__).parent / \"configs\" / \"covid19_cxr.yaml\"\n", + " )\n", + " if not os.path.exists(os.path.join(root, \"covid19_cxr-metadata-pyhealth.csv\")):\n", + " self.prepare_metadata(root)\n", + " default_tables = [\"covid19_cxr\"]\n", + " super().__init__(\n", + " root=root,\n", + " tables=default_tables,\n", + " dataset_name=dataset_name or \"covid19_cxr\",\n", + " config_path=config_path,\n", + " )\n", + " return\n", + "\n", + " def prepare_metadata(self, root: str) -> None:\n", + " \"\"\"Prepare metadata for the COVID-19 CXR dataset.\n", + "\n", + " Args:\n", + " root: Root directory containing the dataset files.\n", + "\n", + " This method:\n", + " 1. Reads metadata from Excel files for each class\n", + " 2. Processes file paths and labels\n", + " 3. Combines all data into a single DataFrame\n", + " 4. Saves the processed metadata to a CSV file\n", + " \"\"\"\n", + " # process and merge raw xlsx files from the dataset\n", + " covid = pd.DataFrame(\n", + " pd.read_excel(f\"{root}/COVID.metadata.xlsx\")\n", + " )\n", + " covid[\"FILE NAME\"] = covid[\"FILE NAME\"].apply(\n", + " lambda x: f\"{root}/COVID/images/{x}.png\"\n", + " )\n", + " covid[\"label\"] = \"COVID\"\n", + " lung_opacity = pd.DataFrame(\n", + " pd.read_excel(f\"{root}/Lung_Opacity.metadata.xlsx\")\n", + " )\n", + " lung_opacity[\"FILE NAME\"] = lung_opacity[\"FILE NAME\"].apply(\n", + " lambda x: f\"{root}/Lung_Opacity/images/{x}.png\"\n", + " )\n", + " lung_opacity[\"label\"] = \"Lung Opacity\"\n", + " normal = pd.DataFrame(\n", + " pd.read_excel(f\"{root}/Normal.metadata.xlsx\")\n", + " )\n", + " normal[\"FILE NAME\"] = normal[\"FILE NAME\"].apply(\n", + " lambda x: x.capitalize()\n", + " )\n", + " normal[\"FILE NAME\"] = normal[\"FILE NAME\"].apply(\n", + " lambda x: f\"{root}/Normal/images/{x}.png\"\n", + " )\n", + " normal[\"label\"] = \"Normal\"\n", + " viral_pneumonia = pd.DataFrame(\n", + " pd.read_excel(f\"{root}/Viral Pneumonia.metadata.xlsx\")\n", + " )\n", + " viral_pneumonia[\"FILE NAME\"] = viral_pneumonia[\"FILE NAME\"].apply(\n", + " lambda x: f\"{root}/Viral Pneumonia/images/{x}.png\"\n", + " )\n", + " viral_pneumonia[\"label\"] = \"Viral Pneumonia\"\n", + " df = pd.concat(\n", + " [covid, lung_opacity, normal, viral_pneumonia],\n", + " axis=0,\n", + " ignore_index=True\n", + " )\n", + " df = df.drop(columns=[\"FORMAT\", \"SIZE\"])\n", + " df.columns = [\"path\", \"url\", \"label\"]\n", + " for path in df.path:\n", + " assert os.path.isfile(path), f\"File {path} does not exist\"\n", + " df.to_csv(\n", + " os.path.join(root, \"covid19_cxr-metadata-pyhealth.csv\"),\n", + " index=False\n", + " )\n", + " return\n", + "\n", + " @property\n", + " def default_task(self) -> COVID19CXRClassification:\n", + " \"\"\"Returns the default task for this dataset.\n", + "\n", + " Returns:\n", + " COVID19CXRClassification: The default classification task.\n", + " \"\"\"\n", + " return COVID19CXRClassification()" + ], + "metadata": { + "id": "xGpZNCqhAVgq" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "#### Code Breakdown\n", + "Taking a closer look, the init() function is practically the same as our MIMIC3 implementation. But, the one difference is we have a **prepare_metadata()** function that constructs a metadata to be used for our BaseDataset. Looking closer at this function, we can see that:\n", + "\n", + "1. **Reading Excel metadata files**: The function reads four separate Excel files containing metadata for each disease category:\n", + " ```python\n", + " covid = pd.DataFrame(pd.read_excel(f\"{root}/COVID.metadata.xlsx\"))\n", + " lung_opacity = pd.DataFrame(pd.read_excel(f\"{root}/Lung_Opacity.metadata.xlsx\"))\n", + " normal = pd.DataFrame(pd.read_excel(f\"{root}/Normal.metadata.xlsx\"))\n", + " viral_pneumonia = pd.DataFrame(pd.read_excel(f\"{root}/Viral Pneumonia.metadata.xlsx\"))\n", + " ```\n", + "\n", + "2. **Constructing file paths**: For each category, it builds the complete file paths by taking the filename from the Excel metadata and prepending the appropriate directory path:\n", + " ```python\n", + " covid[\"FILE NAME\"] = covid[\"FILE NAME\"].apply(\n", + " lambda x: f\"{root}/COVID/images/{x}.png\"\n", + " )\n", + " lung_opacity[\"FILE NAME\"] = lung_opacity[\"FILE NAME\"].apply(\n", + " lambda x: f\"{root}/Lung_Opacity/images/{x}.png\"\n", + " )\n", + " # Special handling for Normal images with capitalization\n", + " normal[\"FILE NAME\"] = normal[\"FILE NAME\"].apply(lambda x: x.capitalize())\n", + " normal[\"FILE NAME\"] = normal[\"FILE NAME\"].apply(\n", + " lambda x: f\"{root}/Normal/images/{x}.png\"\n", + " )\n", + " ```\n", + "\n", + "3. **Adding labels**: Each DataFrame gets a \"label\" column with the corresponding disease category:\n", + " ```python\n", + " covid[\"label\"] = \"COVID\"\n", + " lung_opacity[\"label\"] = \"Lung Opacity\"\n", + " normal[\"label\"] = \"Normal\"\n", + " viral_pneumonia[\"label\"] = \"Viral Pneumonia\"\n", + " ```\n", + "\n", + "4. **Combining and cleaning**: All four DataFrames are concatenated into a single DataFrame, and unnecessary columns are dropped:\n", + " ```python\n", + " df = pd.concat([covid, lung_opacity, normal, viral_pneumonia], axis=0, ignore_index=True)\n", + " df = df.drop(columns=[\"FORMAT\", \"SIZE\"])\n", + " ```\n", + "\n", + "5. **Renaming columns**: The final DataFrame columns are standardized to match the expected schema (below):\n", + " ```python\n", + " df.columns = [\"path\", \"url\", \"label\"]\n", + " ```\n", + "\n", + "6. **Validation**: The function verifies that all image files actually exist on disk:\n", + " ```python\n", + " for path in df.path:\n", + " assert os.path.isfile(path), f\"File {path} does not exist\"\n", + " ```\n", + "\n", + "7. **Saving processed metadata**: The combined and cleaned metadata is saved as a CSV file:\n", + " ```python\n", + " df.to_csv(os.path.join(root, \"covid19_cxr-metadata-pyhealth.csv\"), index=False)\n", + " ```\n", + "\n", + "This preprocessing step transforms the original dataset's scattered Excel metadata files into a single, standardized CSV file that the BaseDataset can easily consume according to the YAML configuration." + ], + "metadata": { + "id": "NG5Prgf3B8Yz" + } + }, + { + "cell_type": "markdown", + "source": [ + "#### **2. Defining covid19_cxr.yaml**\n", + "Once you essentially define your own metadata table, we can define a config.yaml file that takes all of these into account such that we can easily access all of the images in our Events() format.\n", + "\n", + "\n", + "\n", + "```\n", + "version: \"5.0\"\n", + "tables:\n", + " covid19_cxr:\n", + " file_path: \"covid19_cxr-metadata-pyhealth.csv\"\n", + " patient_id: null\n", + " timestamp: null\n", + " attributes:\n", + " - \"path\"\n", + " - \"url\"\n", + " - \"label\"\n", + " ```\n", + "\n", + "You'll see the typical **tables** and other necessary definitions. Taking a closer look at the **attributes:**, we can see 3 key columns that we've created from earlier **path**, **url**, **label** that characterize each X-ray.\n", + "\n", + "These attributes are now directly explorable by any user using the Event.path or Event.url notation from earlier." + ], + "metadata": { + "id": "hmcEoCXnBqIL" + } + }, + { + "cell_type": "markdown", + "source": [ + "If you find it useful, please give us a star ⭐ (fork, and watch) at https://github.com/sunlabuiuc/PyHealth.\n", + "\n", + "Thanks very much for your support!" + ], + "metadata": { + "id": "89v82LIUbTE_" + } + } + ], + "metadata": { + "colab": { + "provenance": [], + "machine_shape": "hm", + "gpuType": "A100" + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + }, + "accelerator": "GPU" + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/examples/tutorials/orig_tutorial_pyhealth_tasks.ipynb b/examples/tutorials/orig_tutorial_pyhealth_tasks.ipynb new file mode 100644 index 000000000..38a044829 --- /dev/null +++ b/examples/tutorials/orig_tutorial_pyhealth_tasks.ipynb @@ -0,0 +1,3559 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "Wr6CSIDPiYNi" + }, + "source": [ + "# **Table of Contents**\n", + "In this tutorial, we will go over the following:\n", + "\n", + "1. **Writing your own [pyhealth.task](https://pyhealth.readthedocs.io/en/latest/api/tasks.html)** with two examples\n", + "2. **Using it with the rest of the pipeline.**\n", + "\n", + "As a reminder, **pyhealth.tasks** directly builds off of **pyhealth.datasets**.\n", + "\n", + "![Image description](https://drive.google.com/uc?export=view&id=1hHJcavXqisH9JEMqEVtE4TqEg_E489l5)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "Dbz1YJ2nqOSN", + "outputId": "9ab52cfc-df1a-4ca9-f5ea-e007da49b681" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Requirement already satisfied: pyhealth in /usr/local/lib/python3.12/dist-packages (2.0.0)\n", + "Requirement already satisfied: accelerate in /usr/local/lib/python3.12/dist-packages (from pyhealth) (1.13.0)\n", + "Requirement already satisfied: dask~=2025.11.0 in /usr/local/lib/python3.12/dist-packages (from dask[complete]~=2025.11.0->pyhealth) (2025.11.0)\n", + "Requirement already satisfied: einops>=0.8.0 in /usr/local/lib/python3.12/dist-packages (from pyhealth) (0.8.2)\n", + "Requirement already satisfied: linear-attention-transformer>=0.19.1 in /usr/local/lib/python3.12/dist-packages (from pyhealth) (0.19.1)\n", + "Requirement already satisfied: litdata~=0.2.59 in /usr/local/lib/python3.12/dist-packages (from pyhealth) (0.2.61)\n", + "Requirement already satisfied: mne~=1.10.0 in /usr/local/lib/python3.12/dist-packages (from pyhealth) (1.10.2)\n", + "Requirement already satisfied: more-itertools~=10.8.0 in /usr/local/lib/python3.12/dist-packages (from pyhealth) (10.8.0)\n", + "Requirement already satisfied: narwhals~=2.13.0 in /usr/local/lib/python3.12/dist-packages (from pyhealth) (2.13.0)\n", + "Requirement already satisfied: networkx in /usr/local/lib/python3.12/dist-packages (from pyhealth) (3.6.1)\n", + "Requirement already satisfied: numpy~=2.2.0 in /usr/local/lib/python3.12/dist-packages (from pyhealth) (2.2.6)\n", + "Requirement already satisfied: ogb>=1.3.5 in /usr/local/lib/python3.12/dist-packages (from pyhealth) (1.3.6)\n", + "Requirement already satisfied: pandas~=2.3.1 in /usr/local/lib/python3.12/dist-packages (from pyhealth) (2.3.3)\n", + "Requirement already satisfied: peft in /usr/local/lib/python3.12/dist-packages (from pyhealth) (0.18.1)\n", + "Requirement already satisfied: polars~=1.35.2 in /usr/local/lib/python3.12/dist-packages (from pyhealth) (1.35.2)\n", + "Requirement already satisfied: pyarrow~=22.0.0 in /usr/local/lib/python3.12/dist-packages (from pyhealth) (22.0.0)\n", + "Requirement already satisfied: pydantic~=2.11.7 in /usr/local/lib/python3.12/dist-packages (from pyhealth) (2.11.10)\n", + "Requirement already satisfied: rdkit in /usr/local/lib/python3.12/dist-packages (from pyhealth) (2025.9.6)\n", + "Requirement already satisfied: scikit-learn~=1.7.0 in /usr/local/lib/python3.12/dist-packages (from pyhealth) (1.7.2)\n", + "Requirement already satisfied: torchvision in /usr/local/lib/python3.12/dist-packages (from pyhealth) (0.22.1)\n", + "Requirement already satisfied: torch~=2.7.1 in /usr/local/lib/python3.12/dist-packages (from pyhealth) (2.7.1)\n", + "Requirement already satisfied: tqdm in /usr/local/lib/python3.12/dist-packages (from pyhealth) (4.67.3)\n", + "Requirement already satisfied: transformers~=4.53.2 in /usr/local/lib/python3.12/dist-packages (from pyhealth) (4.53.3)\n", + "Requirement already satisfied: urllib3~=2.5.0 in /usr/local/lib/python3.12/dist-packages (from pyhealth) (2.5.0)\n", + "Requirement already satisfied: click>=8.1 in /usr/local/lib/python3.12/dist-packages (from dask~=2025.11.0->dask[complete]~=2025.11.0->pyhealth) (8.3.1)\n", + "Requirement already satisfied: cloudpickle>=3.0.0 in /usr/local/lib/python3.12/dist-packages (from dask~=2025.11.0->dask[complete]~=2025.11.0->pyhealth) (3.1.2)\n", + "Requirement already satisfied: fsspec>=2021.09.0 in /usr/local/lib/python3.12/dist-packages (from dask~=2025.11.0->dask[complete]~=2025.11.0->pyhealth) (2025.3.0)\n", + "Requirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.12/dist-packages (from dask~=2025.11.0->dask[complete]~=2025.11.0->pyhealth) (26.0)\n", + "Requirement already satisfied: partd>=1.4.0 in /usr/local/lib/python3.12/dist-packages (from dask~=2025.11.0->dask[complete]~=2025.11.0->pyhealth) (1.4.2)\n", + "Requirement already satisfied: pyyaml>=5.3.1 in /usr/local/lib/python3.12/dist-packages (from dask~=2025.11.0->dask[complete]~=2025.11.0->pyhealth) (6.0.3)\n", + "Requirement already satisfied: toolz>=0.10.0 in /usr/local/lib/python3.12/dist-packages (from dask~=2025.11.0->dask[complete]~=2025.11.0->pyhealth) (0.12.1)\n", + "Requirement already satisfied: lz4>=4.3.2 in /usr/local/lib/python3.12/dist-packages (from dask[complete]~=2025.11.0->pyhealth) (4.4.5)\n", + "Requirement already satisfied: axial-positional-embedding in /usr/local/lib/python3.12/dist-packages (from linear-attention-transformer>=0.19.1->pyhealth) (0.3.12)\n", + "Requirement already satisfied: linformer>=0.1.0 in /usr/local/lib/python3.12/dist-packages (from linear-attention-transformer>=0.19.1->pyhealth) (0.2.3)\n", + "Requirement already satisfied: local-attention in /usr/local/lib/python3.12/dist-packages (from linear-attention-transformer>=0.19.1->pyhealth) (1.11.2)\n", + "Requirement already satisfied: product-key-memory>=0.1.5 in /usr/local/lib/python3.12/dist-packages (from linear-attention-transformer>=0.19.1->pyhealth) (0.3.0)\n", + "Requirement already satisfied: lightning-utilities in /usr/local/lib/python3.12/dist-packages (from litdata~=0.2.59->pyhealth) (0.15.3)\n", + "Requirement already satisfied: filelock in /usr/local/lib/python3.12/dist-packages (from litdata~=0.2.59->pyhealth) (3.25.2)\n", + "Requirement already satisfied: boto3 in /usr/local/lib/python3.12/dist-packages (from litdata~=0.2.59->pyhealth) (1.42.72)\n", + "Requirement already satisfied: requests in /usr/local/lib/python3.12/dist-packages (from litdata~=0.2.59->pyhealth) (2.32.4)\n", + "Requirement already satisfied: tifffile in /usr/local/lib/python3.12/dist-packages (from litdata~=0.2.59->pyhealth) (2026.3.3)\n", + "Requirement already satisfied: obstore in /usr/local/lib/python3.12/dist-packages (from litdata~=0.2.59->pyhealth) (0.9.2)\n", + "Requirement already satisfied: decorator in /usr/local/lib/python3.12/dist-packages (from mne~=1.10.0->pyhealth) (4.4.2)\n", + "Requirement already satisfied: jinja2 in /usr/local/lib/python3.12/dist-packages (from mne~=1.10.0->pyhealth) (3.1.6)\n", + "Requirement already satisfied: lazy-loader>=0.3 in /usr/local/lib/python3.12/dist-packages (from mne~=1.10.0->pyhealth) (0.5)\n", + "Requirement already satisfied: matplotlib>=3.7 in /usr/local/lib/python3.12/dist-packages (from mne~=1.10.0->pyhealth) (3.10.0)\n", + "Requirement already satisfied: pooch>=1.5 in /usr/local/lib/python3.12/dist-packages (from mne~=1.10.0->pyhealth) (1.9.0)\n", + "Requirement already satisfied: scipy>=1.11 in /usr/local/lib/python3.12/dist-packages (from mne~=1.10.0->pyhealth) (1.16.3)\n", + "Requirement already satisfied: six>=1.12.0 in /usr/local/lib/python3.12/dist-packages (from ogb>=1.3.5->pyhealth) (1.17.0)\n", + "Requirement already satisfied: outdated>=0.2.0 in /usr/local/lib/python3.12/dist-packages (from ogb>=1.3.5->pyhealth) (0.2.2)\n", + "Requirement already satisfied: python-dateutil>=2.8.2 in /usr/local/lib/python3.12/dist-packages (from pandas~=2.3.1->pyhealth) (2.9.0.post0)\n", + "Requirement already satisfied: pytz>=2020.1 in /usr/local/lib/python3.12/dist-packages (from pandas~=2.3.1->pyhealth) (2025.2)\n", + "Requirement already satisfied: tzdata>=2022.7 in /usr/local/lib/python3.12/dist-packages (from pandas~=2.3.1->pyhealth) (2025.3)\n", + "Requirement already satisfied: polars-runtime-32==1.35.2 in /usr/local/lib/python3.12/dist-packages (from polars~=1.35.2->pyhealth) (1.35.2)\n", + "Requirement already satisfied: annotated-types>=0.6.0 in /usr/local/lib/python3.12/dist-packages (from pydantic~=2.11.7->pyhealth) (0.7.0)\n", + "Requirement already satisfied: pydantic-core==2.33.2 in /usr/local/lib/python3.12/dist-packages (from pydantic~=2.11.7->pyhealth) (2.33.2)\n", + "Requirement already satisfied: typing-extensions>=4.12.2 in /usr/local/lib/python3.12/dist-packages (from pydantic~=2.11.7->pyhealth) (4.15.0)\n", + "Requirement already satisfied: typing-inspection>=0.4.0 in /usr/local/lib/python3.12/dist-packages (from pydantic~=2.11.7->pyhealth) (0.4.2)\n", + "Requirement already satisfied: joblib>=1.2.0 in /usr/local/lib/python3.12/dist-packages (from scikit-learn~=1.7.0->pyhealth) (1.5.3)\n", + "Requirement already satisfied: threadpoolctl>=3.1.0 in /usr/local/lib/python3.12/dist-packages (from scikit-learn~=1.7.0->pyhealth) (3.6.0)\n", + "Requirement already satisfied: setuptools in /usr/local/lib/python3.12/dist-packages (from torch~=2.7.1->pyhealth) (75.2.0)\n", + "Requirement already satisfied: sympy>=1.13.3 in /usr/local/lib/python3.12/dist-packages (from torch~=2.7.1->pyhealth) (1.14.0)\n", + "Requirement already satisfied: nvidia-cuda-nvrtc-cu12==12.6.77 in /usr/local/lib/python3.12/dist-packages (from torch~=2.7.1->pyhealth) (12.6.77)\n", + "Requirement already satisfied: nvidia-cuda-runtime-cu12==12.6.77 in /usr/local/lib/python3.12/dist-packages (from torch~=2.7.1->pyhealth) (12.6.77)\n", + "Requirement already satisfied: nvidia-cuda-cupti-cu12==12.6.80 in /usr/local/lib/python3.12/dist-packages (from torch~=2.7.1->pyhealth) (12.6.80)\n", + "Requirement already satisfied: nvidia-cudnn-cu12==9.5.1.17 in /usr/local/lib/python3.12/dist-packages (from torch~=2.7.1->pyhealth) (9.5.1.17)\n", + "Requirement already satisfied: nvidia-cublas-cu12==12.6.4.1 in /usr/local/lib/python3.12/dist-packages (from torch~=2.7.1->pyhealth) (12.6.4.1)\n", + "Requirement already satisfied: nvidia-cufft-cu12==11.3.0.4 in /usr/local/lib/python3.12/dist-packages (from torch~=2.7.1->pyhealth) (11.3.0.4)\n", + "Requirement already satisfied: nvidia-curand-cu12==10.3.7.77 in /usr/local/lib/python3.12/dist-packages (from torch~=2.7.1->pyhealth) (10.3.7.77)\n", + "Requirement already satisfied: nvidia-cusolver-cu12==11.7.1.2 in /usr/local/lib/python3.12/dist-packages (from torch~=2.7.1->pyhealth) (11.7.1.2)\n", + "Requirement already satisfied: nvidia-cusparse-cu12==12.5.4.2 in /usr/local/lib/python3.12/dist-packages (from torch~=2.7.1->pyhealth) (12.5.4.2)\n", + "Requirement already satisfied: nvidia-cusparselt-cu12==0.6.3 in /usr/local/lib/python3.12/dist-packages (from torch~=2.7.1->pyhealth) (0.6.3)\n", + "Requirement already satisfied: nvidia-nccl-cu12==2.26.2 in /usr/local/lib/python3.12/dist-packages (from torch~=2.7.1->pyhealth) (2.26.2)\n", + "Requirement already satisfied: nvidia-nvtx-cu12==12.6.77 in /usr/local/lib/python3.12/dist-packages (from torch~=2.7.1->pyhealth) (12.6.77)\n", + "Requirement already satisfied: nvidia-nvjitlink-cu12==12.6.85 in /usr/local/lib/python3.12/dist-packages (from torch~=2.7.1->pyhealth) (12.6.85)\n", + "Requirement already satisfied: nvidia-cufile-cu12==1.11.1.6 in /usr/local/lib/python3.12/dist-packages (from torch~=2.7.1->pyhealth) (1.11.1.6)\n", + "Requirement already satisfied: triton==3.3.1 in /usr/local/lib/python3.12/dist-packages (from torch~=2.7.1->pyhealth) (3.3.1)\n", + "Requirement already satisfied: huggingface-hub<1.0,>=0.30.0 in /usr/local/lib/python3.12/dist-packages (from transformers~=4.53.2->pyhealth) (0.36.2)\n", + "Requirement already satisfied: regex!=2019.12.17 in /usr/local/lib/python3.12/dist-packages (from transformers~=4.53.2->pyhealth) (2025.11.3)\n", + "Requirement already satisfied: tokenizers<0.22,>=0.21 in /usr/local/lib/python3.12/dist-packages (from transformers~=4.53.2->pyhealth) (0.21.4)\n", + "Requirement already satisfied: safetensors>=0.4.3 in /usr/local/lib/python3.12/dist-packages (from transformers~=4.53.2->pyhealth) (0.7.0)\n", + "Requirement already satisfied: psutil in /usr/local/lib/python3.12/dist-packages (from accelerate->pyhealth) (5.9.5)\n", + "Requirement already satisfied: Pillow in /usr/local/lib/python3.12/dist-packages (from rdkit->pyhealth) (11.3.0)\n", + "Requirement already satisfied: hf-xet<2.0.0,>=1.1.3 in /usr/local/lib/python3.12/dist-packages (from huggingface-hub<1.0,>=0.30.0->transformers~=4.53.2->pyhealth) (1.4.2)\n", + "Requirement already satisfied: contourpy>=1.0.1 in /usr/local/lib/python3.12/dist-packages (from matplotlib>=3.7->mne~=1.10.0->pyhealth) (1.3.3)\n", + "Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.12/dist-packages (from matplotlib>=3.7->mne~=1.10.0->pyhealth) (0.12.1)\n", + "Requirement already satisfied: fonttools>=4.22.0 in /usr/local/lib/python3.12/dist-packages (from matplotlib>=3.7->mne~=1.10.0->pyhealth) (4.62.1)\n", + "Requirement already satisfied: kiwisolver>=1.3.1 in /usr/local/lib/python3.12/dist-packages (from matplotlib>=3.7->mne~=1.10.0->pyhealth) (1.5.0)\n", + "Requirement already satisfied: pyparsing>=2.3.1 in /usr/local/lib/python3.12/dist-packages (from matplotlib>=3.7->mne~=1.10.0->pyhealth) (3.3.2)\n", + "Requirement already satisfied: littleutils in /usr/local/lib/python3.12/dist-packages (from outdated>=0.2.0->ogb>=1.3.5->pyhealth) (0.2.4)\n", + "Requirement already satisfied: locket in /usr/local/lib/python3.12/dist-packages (from partd>=1.4.0->dask~=2025.11.0->dask[complete]~=2025.11.0->pyhealth) (1.0.0)\n", + "Requirement already satisfied: platformdirs>=2.5.0 in /usr/local/lib/python3.12/dist-packages (from pooch>=1.5->mne~=1.10.0->pyhealth) (4.9.4)\n", + "Requirement already satisfied: colt5-attention>=0.10.14 in /usr/local/lib/python3.12/dist-packages (from product-key-memory>=0.1.5->linear-attention-transformer>=0.19.1->pyhealth) (0.11.1)\n", + "Requirement already satisfied: charset_normalizer<4,>=2 in /usr/local/lib/python3.12/dist-packages (from requests->litdata~=0.2.59->pyhealth) (3.4.6)\n", + "Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.12/dist-packages (from requests->litdata~=0.2.59->pyhealth) (3.11)\n", + "Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.12/dist-packages (from requests->litdata~=0.2.59->pyhealth) (2026.2.25)\n", + "Requirement already satisfied: mpmath<1.4,>=1.1.0 in /usr/local/lib/python3.12/dist-packages (from sympy>=1.13.3->torch~=2.7.1->pyhealth) (1.3.0)\n", + "Requirement already satisfied: botocore<1.43.0,>=1.42.72 in /usr/local/lib/python3.12/dist-packages (from boto3->litdata~=0.2.59->pyhealth) (1.42.72)\n", + "Requirement already satisfied: jmespath<2.0.0,>=0.7.1 in /usr/local/lib/python3.12/dist-packages (from boto3->litdata~=0.2.59->pyhealth) (1.1.0)\n", + "Requirement already satisfied: s3transfer<0.17.0,>=0.16.0 in /usr/local/lib/python3.12/dist-packages (from boto3->litdata~=0.2.59->pyhealth) (0.16.0)\n", + "Requirement already satisfied: distributed==2025.11.0 in /usr/local/lib/python3.12/dist-packages (from dask~=2025.11.0->dask[complete]~=2025.11.0->pyhealth) (2025.11.0)\n", + "Requirement already satisfied: bokeh>=3.1.0 in /usr/local/lib/python3.12/dist-packages (from dask~=2025.11.0->dask[complete]~=2025.11.0->pyhealth) (3.8.2)\n", + "Requirement already satisfied: msgpack>=1.0.2 in /usr/local/lib/python3.12/dist-packages (from distributed==2025.11.0->dask~=2025.11.0->dask[complete]~=2025.11.0->pyhealth) (1.1.2)\n", + "Requirement already satisfied: sortedcontainers>=2.0.5 in /usr/local/lib/python3.12/dist-packages (from distributed==2025.11.0->dask~=2025.11.0->dask[complete]~=2025.11.0->pyhealth) (2.4.0)\n", + "Requirement already satisfied: tblib>=1.6.0 in /usr/local/lib/python3.12/dist-packages (from distributed==2025.11.0->dask~=2025.11.0->dask[complete]~=2025.11.0->pyhealth) (3.2.2)\n", + "Requirement already satisfied: tornado>=6.2.0 in /usr/local/lib/python3.12/dist-packages (from distributed==2025.11.0->dask~=2025.11.0->dask[complete]~=2025.11.0->pyhealth) (6.5.1)\n", + "Requirement already satisfied: zict>=3.0.0 in /usr/local/lib/python3.12/dist-packages (from distributed==2025.11.0->dask~=2025.11.0->dask[complete]~=2025.11.0->pyhealth) (3.0.0)\n", + "Requirement already satisfied: MarkupSafe>=2.0 in /usr/local/lib/python3.12/dist-packages (from jinja2->mne~=1.10.0->pyhealth) (3.0.3)\n", + "Requirement already satisfied: hyper-connections>=0.1.8 in /usr/local/lib/python3.12/dist-packages (from local-attention->linear-attention-transformer>=0.19.1->pyhealth) (0.4.9)\n", + "Requirement already satisfied: xyzservices>=2021.09.1 in /usr/local/lib/python3.12/dist-packages (from bokeh>=3.1.0->dask~=2025.11.0->dask[complete]~=2025.11.0->pyhealth) (2025.11.0)\n", + "Requirement already satisfied: torch-einops-utils>=0.0.20 in /usr/local/lib/python3.12/dist-packages (from hyper-connections>=0.1.8->local-attention->linear-attention-transformer>=0.19.1->pyhealth) (0.0.30)\n" + ] + } + ], + "source": [ + "!pip install pyhealth" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "1e_FEPyho3zx" + }, + "source": [ + "### **BaseTask**\n", + "\n", + "There's a couple of things to keep in mind here. First, every task inherits the BaseTask class, which looks like\n", + "\n", + "\n", + "\n", + "```\n", + "class BaseTask(ABC):\n", + " task_name: str\n", + " input_schema: Dict[str, str]\n", + " output_schema: Dict[str, str]\n", + "\n", + " def pre_filter(self, df: pl.LazyFrame) -> pl.LazyFrame:\n", + " return df\n", + "\n", + " @abstractmethod\n", + " def __call__(self, patient) -> List[Dict]:\n", + " raise NotImplementedError\n", + "```\n", + "\n", + "\n", + "It defines a couple of key things:\n", + "\n", + "\n", + "1. The call function where we process the extracted data into a usable format from each patient. **(Note: The patient variable here effectively just represents a sample unit defined by the pyhealth.dataset module earlier.)**\n", + "\n", + "\n", + "\n", + "2. The input_schema and output_schema, which define the format of the model input and model output. This can range a wide variety of datatypes. While we offer [processors](https://github.com/sunlabuiuc/PyHealth/tree/master/pyhealth/processors) that take explicitly defined datatypes and processes them for use in training existing models on PyHealth. However, these pre-defined datatypes **are not required** and can effectively be anything for your purposes. However, We **recommend** schemas primarily for documentation purposes, and for direct use with our lightweight trainers.\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "_uHLk9voEXZ8" + }, + "source": [ + "![image.png](data:image/png;base64,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)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Zpo_w5Esimar" + }, + "source": [ + "### **Example 1: Medical Coding**\n", + "\n", + "Here, we want to construct a simple medical coding task where effectively we want to translate every piece of text in a patient's history to a set of medical codes. Here, you'll notice a couple of things:\n", + "\n", + "1. The processing of data is functionally the same as exploring data with PyHealth datasets [here](https://colab.research.google.com/drive/1vI_oljc7rU5ocsC26ITM7HUgD5SGZkFE?usp=sharing)\n", + "2. We have defined a 'text' input for our models and 'icd_codes' as our output. These explicitly outline how pyhealth models will interact with the \"pyhealth.task\" and for interested users, what the task is attempting to accomplish.\n", + "3. Here we only need to define 3 specific things:\n", + "\n", + "\n", + "```\n", + "input_schema : {\"our feature identifier\" : \"processor_name\"}\n", + "output_schema : {\"our label\" : \"type of label\"}\n", + "```\n", + "\n", + "\n", + "\n", + "See the API for our processors [here](https://pyhealth.readthedocs.io/en/latest/api/processors.html). Each processor effectively defines how the processed data will be represented in tensor space. You can imagine it being equivalent to a tokenizer in LLMs, a image transform in medical imaging, and a static embedding model for various categorical models." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "DjySbbSKtyqc" + }, + "outputs": [], + "source": [ + "from pyhealth.data import Patient\n", + "from pyhealth.tasks.base_task import BaseTask\n", + "from typing import Dict, List\n", + "from pyhealth.processors import TextProcessor, MultiLabelProcessor\n", + "import polars as pl\n", + "class MIMIC3ICD9Coding(BaseTask):\n", + " \"\"\"Medical coding task for MIMIC-III using ICD-9 codes.\n", + "\n", + " This task uses clinical notes to predict ICD-9 codes for a patient.\n", + "\n", + " Args:\n", + " task_name: Name of the task\n", + " input_schema: Definition of the input data schema\n", + " output_schema: Definition of the output data schema\n", + " \"\"\"\n", + " task_name: str = \"mimic3_icd9_coding\"\n", + " input_schema: Dict[str, str] = {\"text\": TextProcessor}\n", + " output_schema: Dict[str, str] = {\"icd_codes\": MultiLabelProcessor}\n", + "\n", + " def pre_filter(self, df: pl.LazyFrame) -> pl.LazyFrame:\n", + " filtered_df = df.filter(\n", + " pl.col(\"patient_id\").is_in(\n", + " df.filter(pl.col(\"event_type\") == \"noteevents\")\n", + " .select(\"patient_id\")\n", + " .unique()\n", + " .collect()\n", + " .to_series()\n", + " )\n", + " )\n", + " return filtered_df\n", + "\n", + " def __call__(self, patient: Patient) -> List[Dict]:\n", + " \"\"\"Process a patient and extract the clinical notes and ICD-9 codes.\n", + "\n", + " Args:\n", + " patient: Patient object containing events\n", + "\n", + " Returns:\n", + " List of samples, each containing text and ICD codes\n", + " \"\"\"\n", + " samples = []\n", + " text = \"\"\n", + " icd_codes = set()\n", + "\n", + " diagnoses_icd = patient.get_events(\n", + " event_type=\"diagnoses_icd\",\n", + " )\n", + " procedures_icd = patient.get_events(\n", + " event_type=\"procedures_icd\",\n", + " )\n", + " noteevents = patient.get_events(\n", + " event_type=\"noteevents\",\n", + " )\n", + "\n", + "\n", + " for note in noteevents:\n", + " text += \" \" + note.text\n", + "\n", + " diagnoses_icd = [event.icd9_code for event in diagnoses_icd]\n", + " procedures_icd = [event.icd9_code for event in procedures_icd]\n", + " icd_codes = list(set(diagnoses_icd + procedures_icd))\n", + "\n", + " samples.append({\n", + " \"patient_id\": patient.patient_id,\n", + " \"text\": text,\n", + " \"icd_codes\": icd_codes\n", + " })\n", + "\n", + " return samples\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "ZDVuIMBNkV1e" + }, + "source": [ + "### Connecting the medical coding task to the MIMIC3 dataset." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "6s-hW_4zmELB", + "outputId": "f48cc318-c453-43a6-a00f-9e7a440446a1" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "No config path provided, using default config\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.datasets.mimic3:No config path provided, using default config\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Initializing mimic3 dataset from https://storage.googleapis.com/pyhealth/Synthetic_MIMIC-III (dev mode: False)\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.datasets.base_dataset:Initializing mimic3 dataset from https://storage.googleapis.com/pyhealth/Synthetic_MIMIC-III (dev mode: False)\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Setting task mimic3_icd9_coding for mimic3 base dataset...\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.datasets.base_dataset:Setting task mimic3_icd9_coding for mimic3 base dataset...\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "No cache_dir provided. Using default cache dir: /root/.cache/pyhealth/54ab2756-e441-5796-8994-6521684b496b\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.datasets.base_dataset:No cache_dir provided. Using default cache dir: /root/.cache/pyhealth/54ab2756-e441-5796-8994-6521684b496b\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Applying task transformations on data with 1 workers...\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.datasets.base_dataset:Applying task transformations on data with 1 workers...\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Detected Jupyter notebook environment, setting num_workers to 1\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.datasets.base_dataset:Detected Jupyter notebook environment, setting num_workers to 1\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Single worker mode, processing sequentially\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.datasets.base_dataset:Single worker mode, processing sequentially\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Worker 0 started processing 49993 patients. (Polars threads: 2)\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.datasets.base_dataset:Worker 0 started processing 49993 patients. (Polars threads: 2)\n", + " 0%| | 0/49993 [00:00 0:\n", + " print(\"First sample:\")\n", + " print(f\" - Text length: {len(samples[0]['text'])} characters\")\n", + " print(f\" - Number of ICD codes: {len(samples[0]['icd_codes'])}\")\n", + " if len(samples[0]['icd_codes']) > 0:\n", + " print(f\" - Sample ICD codes: {samples[0]['icd_codes'][:5] if len(samples[0]['icd_codes']) > 5 else samples[0]['icd_codes']}\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "dFBpilGxmHj_" + }, + "source": [ + "#### Dataset Splitting for Training Purposes." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "sKXwIMqumG5l" + }, + "outputs": [], + "source": [ + "from pyhealth.datasets import split_by_sample\n", + "\n", + "\n", + "train_dataset, val_dataset, test_dataset = split_by_sample(\n", + " dataset=samples,\n", + " ratios=[0.7, 0.1, 0.2]\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Q2W0_EAHmN9I" + }, + "outputs": [], + "source": [ + "from pyhealth.datasets import get_dataloader\n", + "\n", + "\n", + "train_dataloader = get_dataloader(train_dataset, batch_size=32, shuffle=True)\n", + "val_dataloader = get_dataloader(val_dataset, batch_size=32, shuffle=False)\n", + "test_dataloader = get_dataloader(test_dataset, batch_size=32, shuffle=False)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 1000, + "referenced_widgets": [ + "7a9122563c9e4687bdee551f80e6a04c", + "76820c961c5546eea07dffaee4fc1afe", + "b95f052369ca4c9aa408202a79605ad5", + "0de857438cdd48be99a9976d55f17d90", + "0a79aae3c59841b7997121f1dfc9018b", + "63e183f44074438b9668cb550609ef6e", + "0c902e1ced3c4f55aa24fd89f489a868", + "24a2f7608ff140068dca3da173d800f2", + "0e04bc0fd737470eabcc2e8b096ebd0b", + "79670c3c4caa477c8d9f532a67713bd1", + "73ef445b199549f0b9b373c8c811086e", + "19ef55e52f564055bacaa051e3a5e741", + "847814036a204dd5aec948d54f680c73", + "4d4f9f0c7f2c4b5cb89477736a1be044", + "54fde265e53744949ba84c061daf8052", + "81cd3f0f3550491896178867b92998e9", + "7e4b3d65b6ea4a45a031d0b124935936", + "c3c29ecd8c164cf59b02b109b8b7fff2", + "1305abdd6b2343a992653d0b0ca00ac6", + "89e8167d12ad4cadb221a7ad251dbb0f", + "e61505c4a66849ad939b527cb8d987b3", + "f3de069a2d6941ef8340549574f79b7d", + "15b29ca96820408eb704ef4ffc6a31bf", + "695d2abbe9474d60922fa34a2eb37048", + "6a8edb7b0481458a810aaaf20c31ea2a", + "515d714490244e85ac709cc287e2c969", + "dd9f1067b55e4ba79031de14541d6241", + "1fd4ea84b4fc4b89b3d44c6dd6b33939", + "05f7b1c15e334899ba95697314d1f262", + "9759b8e4fdda4ec99ed55c206323b8bb", + "048fef6a53924f7287500af1aad452fc", + "6ab68fe5e80d4d338a3c90cc6610b8c0", + "d21606905a2848cb924a93729072b0a0", + "3d02a6191a2a4c78a6489e14a8b940c0", + "914494fbc0b94890b5d4ba2f586531dd", + "09e8ed1d23854e3386dd69427e844388", + "f817d9d70b64411ca6c8621aa167f81d", + "faea50f2c8374f00a2812cde1d160035", + "3241772b17c0457daacec72d22e48802", + "19c37da106fc4625818ef41b30b30457", + "6db1a2d475674bdb8da0855aa7cdaf2b", + "466ec22790b44cd0b7708469d5d70fbc", + "a48767e85091415592470d1a82d5017b", + "819dd68e15c4417b8a8660bc736c9b20", + "442bf25d617a4a2b86409415d58086d5", + "dbd0f3bdce2847b98793c0e31489e6e1", + "3b878bf8ee034863a6fc69b76ffa327c", + "379bf5b86d04463d99fa3f0a470fa7d0", + "103ed91a868f4da2b82a22ab7c815624", + "02012ea045354c0e8eb824877e803d29", + "f2cc19a0cc954c2a93896387ace72b52", + "05b026da265749c09e06ce39261b9881", + "9f7219f85d7e4f939538373d372259cf", + "afcb399895c343ba91770fae1f2b6f55", + "ac534e2be9b84087be55cbac903f6b3d" + ] + }, + "id": "aazMWCTGmSKU", + "outputId": "2ca8d1d5-da4b-48fa-a6df-f5fbd252fa69" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stderr", + "text": [ + "/usr/local/lib/python3.12/dist-packages/huggingface_hub/utils/_auth.py:94: UserWarning: \n", + "The secret `HF_TOKEN` does not exist in your Colab secrets.\n", + "To authenticate with the Hugging Face Hub, create a token in your settings tab (https://huggingface.co/settings/tokens), set it as secret in your Google Colab and restart your session.\n", + "You will be able to reuse this secret in all of your notebooks.\n", + "Please note that authentication is recommended but still optional to access public models or datasets.\n", + " warnings.warn(\n" + ] + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "config.json: 0%| | 0.00/385 [00:00\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.trainer:Optimizer: \n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Optimizer params: {'lr': 5e-05}\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.trainer:Optimizer params: {'lr': 5e-05}\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Weight decay: 0.0\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.trainer:Weight decay: 0.0\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Max grad norm: None\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.trainer:Max grad norm: None\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Val dataloader: \n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.trainer:Val dataloader: \n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Monitor: f1_micro\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.trainer:Monitor: f1_micro\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Monitor criterion: max\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.trainer:Monitor criterion: max\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Epochs: 1\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.trainer:Epochs: 1\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Patience: None\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.trainer:Patience: None\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.trainer:\n" + ] + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "Epoch 0 / 1: 0%| | 0/1094 [00:00 List[Dict[str, Any]]:\n", + " \"\"\"Process a patient's chest X-ray data to classify COVID-19 status.\n", + "\n", + " Args:\n", + " patient: A patient object containing chest X-ray data.\n", + "\n", + " Returns:\n", + " List[Dict[str, Any]]: A list containing a single dictionary with:\n", + " - \"image\": Path to the chest X-ray image\n", + " - \"disease\": The disease classification label\n", + "\n", + " Raises:\n", + " AssertionError: If the patient has more than one chest X-ray event.\n", + " \"\"\"\n", + " event = patient.get_events(event_type=\"covid19_cxr\")\n", + " # There should be only one event\n", + " assert len(event) == 1\n", + " event = event[0]\n", + " image = event.path\n", + " disease = event.label\n", + " return [{\"image\": image, \"disease\": disease}]" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "3w9KpgmjljMR" + }, + "source": [ + "#### We apply this task function on the COVID19CXR dataset" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "YxuCmBsmuwNj", + "outputId": "9116441a-4c22-471e-b9f4-0e291b53c7fa" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "--2026-03-20 17:13:58-- https://storage.googleapis.com/pyhealth/covid19_cxr_data/archive.zip\n", + "Resolving storage.googleapis.com (storage.googleapis.com)... 142.250.4.207, 64.233.170.207, 142.251.10.207, ...\n", + "Connecting to storage.googleapis.com (storage.googleapis.com)|142.250.4.207|:443... connected.\n", + "HTTP request sent, awaiting response... 200 OK\n", + "Length: 816029038 (778M) [application/zip]\n", + "Saving to: ‘archive.zip’\n", + "\n", + "archive.zip 100%[===================>] 778.23M 19.7MB/s in 45s \n", + "\n", + "2026-03-20 17:14:44 (17.3 MB/s) - ‘archive.zip’ saved [816029038/816029038]\n", + "\n", + "COVID\n", + "COVID.metadata.xlsx\n", + "Lung_Opacity\n", + "Lung_Opacity.metadata.xlsx\n", + "Normal\n", + "Normal.metadata.xlsx\n", + "README.md.txt\n", + "'Viral Pneumonia'\n", + "'Viral Pneumonia.metadata.xlsx'\n" + ] + } + ], + "source": [ + "!wget -N https://storage.googleapis.com/pyhealth/covid19_cxr_data/archive.zip\n", + "!unzip -q -o archive.zip\n", + "!ls -1 COVID-19_Radiography_Dataset" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "nwnHieQiXcZA", + "outputId": "111ab043-6edf-4480-ea5c-654957b53999" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "No config path provided, using default config\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.datasets.covid19_cxr:No config path provided, using default config\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Initializing covid19_cxr dataset from /content/COVID-19_Radiography_Dataset (dev mode: False)\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.datasets.base_dataset:Initializing covid19_cxr dataset from /content/COVID-19_Radiography_Dataset (dev mode: False)\n" + ] + } + ], + "source": [ + "from pyhealth.datasets import COVID19CXRDataset\n", + "\n", + "\n", + "root = \"/content/COVID-19_Radiography_Dataset\"\n", + "cxr_dataset = COVID19CXRDataset(root)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 731 + }, + "id": "U5p4Eux-u9LV", + "outputId": "a1e171d9-6e2c-4bc9-e4f3-800f21275f8b" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Setting task COVID19CXRClassification for covid19_cxr base dataset...\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.datasets.base_dataset:Setting task COVID19CXRClassification for covid19_cxr base dataset...\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "No cache_dir provided. Using default cache dir: /root/.cache/pyhealth/ebe82b39-fbfc-5f16-8c90-0a3824c58fab\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.datasets.base_dataset:No cache_dir provided. Using default cache dir: /root/.cache/pyhealth/ebe82b39-fbfc-5f16-8c90-0a3824c58fab\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Applying task transformations on data with 1 workers...\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.datasets.base_dataset:Applying task transformations on data with 1 workers...\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Scanning table: covid19_cxr from /content/COVID-19_Radiography_Dataset/covid19_cxr-metadata-pyhealth.csv\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.datasets.base_dataset:Scanning table: covid19_cxr from /content/COVID-19_Radiography_Dataset/covid19_cxr-metadata-pyhealth.csv\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Caching event dataframe to /root/.cache/pyhealth/ebe82b39-fbfc-5f16-8c90-0a3824c58fab/global_event_df.parquet...\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.datasets.base_dataset:Caching event dataframe to /root/.cache/pyhealth/ebe82b39-fbfc-5f16-8c90-0a3824c58fab/global_event_df.parquet...\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Detected Jupyter notebook environment, setting num_workers to 1\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.datasets.base_dataset:Detected Jupyter notebook environment, setting num_workers to 1\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Single worker mode, processing sequentially\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.datasets.base_dataset:Single worker mode, processing sequentially\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Worker 0 started processing 21165 patients. (Polars threads: 2)\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:pyhealth.datasets.base_dataset:Worker 0 started processing 21165 patients. (Polars threads: 2)\n", + " 0%| | 0/21165 [00:00', '>='\nabnormal_labs = patient.get_events(\n event_type=\"lab\",\n filters=[(\"status\", \"!=\", \"high\")] # exclude 'high', keep 'abnormal' and 'critical'\n)\nprint(f\"Non-high abnormal labs: {len(abnormal_labs)}\")\nfor lab in abnormal_labs:\n print(f\" {lab['name']}: {lab['value']} {lab['unit']} — {lab['status']}\")" + "source": "# 3d. Attribute filters: only abnormal or critical lab results\n# Format: [(attribute_name, operator, value), ...]\n# Supported operators: '==', '!=', '<', '<=', '>', '>='\nabnormal_labs = patient.get_events(\n event_type=\"lab\",\n filters=[(\"status\", \"!=\", \"high\")] # exclude 'high', keep 'abnormal' and 'critical'\n)\nprint(f\"Non-high abnormal labs: {len(abnormal_labs)}\")\nfor lab in abnormal_labs:\n print(f\" {lab['name']}: {lab['value']} {lab['unit']} \u2014 {lab['status']}\")" }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], - "source": "# 3e. Multiple filters (AND logic)\ncritical_glucose = patient.get_events(\n event_type=\"lab\",\n filters=[\n (\"name\", \"==\", \"Blood Glucose\"),\n (\"value\", \">\", 200.0),\n ]\n)\nprint(f\"Critical glucose readings (>200 mg/dL): {len(critical_glucose)}\")\nfor lab in critical_glucose:\n print(f\" {lab.timestamp.date()} — {lab['value']} mg/dL\")" + "source": "# 3e. Multiple filters (AND logic)\ncritical_glucose = patient.get_events(\n event_type=\"lab\",\n filters=[\n (\"name\", \"==\", \"Blood Glucose\"),\n (\"value\", \">\", 200.0),\n ]\n)\nprint(f\"Critical glucose readings (>200 mg/dL): {len(critical_glucose)}\")\nfor lab in critical_glucose:\n print(f\" {lab.timestamp.date()} \u2014 {lab['value']} mg/dL\")" }, { "cell_type": "code", @@ -129,40 +136,40 @@ { "cell_type": "markdown", "metadata": {}, - "source": "---\n## Part 4: Realistic Longitudinal Example\n\nLet's build a richer patient record — a 63-year-old with Type 2 diabetes, chronic kidney disease, and polyneuropathy, tracked across three hospital admissions over 18 months." + "source": "---\n## Part 4: Realistic Longitudinal Example\n\nLet's build a richer patient record \u2014 a 63-year-old with Type 2 diabetes, chronic kidney disease, and polyneuropathy, tracked across three hospital admissions over 18 months." }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], - "source": "# A more complete patient record with three admissions\nfull_data = pl.DataFrame(\n {\n \"event_type\": [\n # Admission 1 (Jan 2023)\n \"admission\",\n \"diagnosis\", \"diagnosis\",\n \"lab\", \"lab\", \"lab\",\n \"note\",\n # Admission 2 (Jul 2023)\n \"admission\",\n \"diagnosis\", \"diagnosis\", \"diagnosis\",\n \"lab\", \"lab\",\n # Admission 3 (Jan 2024)\n \"admission\",\n \"diagnosis\",\n \"lab\",\n \"note\",\n ],\n \"timestamp\": [\n # Admission 1\n datetime(2023, 1, 10, 8, 0),\n datetime(2023, 1, 10, 9, 0),\n datetime(2023, 1, 10, 9, 5),\n datetime(2023, 1, 10, 10, 0),\n datetime(2023, 1, 10, 10, 5),\n datetime(2023, 1, 10, 10, 10),\n datetime(2023, 1, 12, 14, 0),\n # Admission 2\n datetime(2023, 7, 20, 8, 0),\n datetime(2023, 7, 20, 9, 0),\n datetime(2023, 7, 20, 9, 5),\n datetime(2023, 7, 20, 9, 10),\n datetime(2023, 7, 20, 10, 0),\n datetime(2023, 7, 20, 10, 5),\n # Admission 3\n datetime(2024, 1, 5, 8, 0),\n datetime(2024, 1, 5, 9, 0),\n datetime(2024, 1, 5, 10, 0),\n datetime(2024, 1, 7, 15, 0),\n ],\n # ── admission columns ──────────────────────────────────────────────────\n \"admission/hadm_id\": [\n \"ADM001\", None, None, None, None, None, None,\n \"ADM002\", None, None, None, None, None,\n \"ADM003\", None, None, None,\n ],\n \"admission/admit_type\": [\n \"EMERGENCY\", None, None, None, None, None, None,\n \"ELECTIVE\", None, None, None, None, None,\n \"URGENT\", None, None, None,\n ],\n # ── diagnosis columns ──────────────────────────────────────────────────\n \"diagnosis/icd_code\": [\n None, \"E11.9\", \"E11.65\", None, None, None, None,\n None, \"E11.22\", \"E11.42\", \"N18.3\", None, None,\n None, \"E11.65\", None, None,\n ],\n \"diagnosis/description\": [\n None,\n \"T2DM without complications\",\n \"T2DM with hyperglycemia\",\n None, None, None, None,\n None,\n \"T2DM with chronic kidney disease\",\n \"T2DM with polyneuropathy\",\n \"Chronic kidney disease, stage 3\",\n None, None,\n None,\n \"T2DM with hyperglycemia\",\n None, None,\n ],\n # ── lab columns ────────────────────────────────────────────────────────\n \"lab/name\": [\n None, None, None,\n \"HbA1c\", \"eGFR\", \"Creatinine\",\n None,\n None, None, None, None,\n \"HbA1c\", \"eGFR\",\n None, None,\n \"HbA1c\",\n None,\n ],\n \"lab/value\": [\n None, None, None,\n 8.5, 52.0, 1.8,\n None,\n None, None, None, None,\n 9.1, 44.0,\n None, None,\n 7.8,\n None,\n ],\n \"lab/unit\": [\n None, None, None,\n \"%\", \"mL/min/1.73m²\", \"mg/dL\",\n None,\n None, None, None, None,\n \"%\", \"mL/min/1.73m²\",\n None, None,\n \"%\",\n None,\n ],\n # ── note columns ───────────────────────────────────────────────────────\n \"note/note_type\": [\n None, None, None, None, None, None,\n \"Discharge Summary\",\n None, None, None, None, None, None,\n None, None, None,\n \"Progress Note\",\n ],\n \"note/text\": [\n None, None, None, None, None, None,\n \"Patient admitted for hyperglycemia management. HbA1c 8.5%. eGFR 52. Discharged on insulin glargine.\",\n None, None, None, None, None, None,\n None, None, None,\n \"HbA1c improved to 7.8%. eGFR stable. Continue current regimen.\",\n ],\n }\n)\n\nrichPatient = Patient(patient_id=\"P999\", data_source=full_data)\nprint(\"Patient P999 record:\")\nprint(f\" Total events: {len(richPatient.get_events())}\")\nprint(f\" Event types present: {list(richPatient.event_type_partitions.keys())}\")" + "source": "# A more complete patient record with three admissions\nfull_data = pl.DataFrame(\n {\n \"event_type\": [\n # Admission 1 (Jan 2023)\n \"admission\",\n \"diagnosis\", \"diagnosis\",\n \"lab\", \"lab\", \"lab\",\n \"note\",\n # Admission 2 (Jul 2023)\n \"admission\",\n \"diagnosis\", \"diagnosis\", \"diagnosis\",\n \"lab\", \"lab\",\n # Admission 3 (Jan 2024)\n \"admission\",\n \"diagnosis\",\n \"lab\",\n \"note\",\n ],\n \"timestamp\": [\n # Admission 1\n datetime(2023, 1, 10, 8, 0),\n datetime(2023, 1, 10, 9, 0),\n datetime(2023, 1, 10, 9, 5),\n datetime(2023, 1, 10, 10, 0),\n datetime(2023, 1, 10, 10, 5),\n datetime(2023, 1, 10, 10, 10),\n datetime(2023, 1, 12, 14, 0),\n # Admission 2\n datetime(2023, 7, 20, 8, 0),\n datetime(2023, 7, 20, 9, 0),\n datetime(2023, 7, 20, 9, 5),\n datetime(2023, 7, 20, 9, 10),\n datetime(2023, 7, 20, 10, 0),\n datetime(2023, 7, 20, 10, 5),\n # Admission 3\n datetime(2024, 1, 5, 8, 0),\n datetime(2024, 1, 5, 9, 0),\n datetime(2024, 1, 5, 10, 0),\n datetime(2024, 1, 7, 15, 0),\n ],\n # \u2500\u2500 admission columns \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n \"admission/hadm_id\": [\n \"ADM001\", None, None, None, None, None, None,\n \"ADM002\", None, None, None, None, None,\n \"ADM003\", None, None, None,\n ],\n \"admission/admit_type\": [\n \"EMERGENCY\", None, None, None, None, None, None,\n \"ELECTIVE\", None, None, None, None, None,\n \"URGENT\", None, None, None,\n ],\n # \u2500\u2500 diagnosis columns \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n \"diagnosis/icd_code\": [\n None, \"E11.9\", \"E11.65\", None, None, None, None,\n None, \"E11.22\", \"E11.42\", \"N18.3\", None, None,\n None, \"E11.65\", None, None,\n ],\n \"diagnosis/description\": [\n None,\n \"T2DM without complications\",\n \"T2DM with hyperglycemia\",\n None, None, None, None,\n None,\n \"T2DM with chronic kidney disease\",\n \"T2DM with polyneuropathy\",\n \"Chronic kidney disease, stage 3\",\n None, None,\n None,\n \"T2DM with hyperglycemia\",\n None, None,\n ],\n # \u2500\u2500 lab columns \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n \"lab/name\": [\n None, None, None,\n \"HbA1c\", \"eGFR\", \"Creatinine\",\n None,\n None, None, None, None,\n \"HbA1c\", \"eGFR\",\n None, None,\n \"HbA1c\",\n None,\n ],\n \"lab/value\": [\n None, None, None,\n 8.5, 52.0, 1.8,\n None,\n None, None, None, None,\n 9.1, 44.0,\n None, None,\n 7.8,\n None,\n ],\n \"lab/unit\": [\n None, None, None,\n \"%\", \"mL/min/1.73m\u00b2\", \"mg/dL\",\n None,\n None, None, None, None,\n \"%\", \"mL/min/1.73m\u00b2\",\n None, None,\n \"%\",\n None,\n ],\n # \u2500\u2500 note columns \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n \"note/note_type\": [\n None, None, None, None, None, None,\n \"Discharge Summary\",\n None, None, None, None, None, None,\n None, None, None,\n \"Progress Note\",\n ],\n \"note/text\": [\n None, None, None, None, None, None,\n \"Patient admitted for hyperglycemia management. HbA1c 8.5%. eGFR 52. Discharged on insulin glargine.\",\n None, None, None, None, None, None,\n None, None, None,\n \"HbA1c improved to 7.8%. eGFR stable. Continue current regimen.\",\n ],\n }\n)\n\nrichPatient = Patient(patient_id=\"P999\", data_source=full_data)\nprint(\"Patient P999 record:\")\nprint(f\" Total events: {len(richPatient.get_events())}\")\nprint(f\" Event types present: {list(richPatient.event_type_partitions.keys())}\")" }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], - "source": "# Query: track HbA1c trend across admissions\nhba1c_labs = richPatient.get_events(\n event_type=\"lab\",\n filters=[(\"name\", \"==\", \"HbA1c\")]\n)\nprint(\"HbA1c Trend:\")\nfor lab in hba1c_labs:\n print(f\" {lab.timestamp.date()} — HbA1c: {lab['value']} {lab['unit']}\")" + "source": "# Query: track HbA1c trend across admissions\nhba1c_labs = richPatient.get_events(\n event_type=\"lab\",\n filters=[(\"name\", \"==\", \"HbA1c\")]\n)\nprint(\"HbA1c Trend:\")\nfor lab in hba1c_labs:\n print(f\" {lab.timestamp.date()} \u2014 HbA1c: {lab['value']} {lab['unit']}\")" }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], - "source": "# Query: get all diagnoses within a specific year (2023)\ndiagnoses_2023 = richPatient.get_events(\n event_type=\"diagnosis\",\n start=datetime(2023, 1, 1),\n end=datetime(2023, 12, 31, 23, 59, 59),\n)\nprint(\"Diagnoses in 2023:\")\nfor dx in diagnoses_2023:\n print(f\" {dx.timestamp.date()} — {dx['icd_code']}: {dx['description']}\")" + "source": "# Query: get all diagnoses within a specific year (2023)\ndiagnoses_2023 = richPatient.get_events(\n event_type=\"diagnosis\",\n start=datetime(2023, 1, 1),\n end=datetime(2023, 12, 31, 23, 59, 59),\n)\nprint(\"Diagnoses in 2023:\")\nfor dx in diagnoses_2023:\n print(f\" {dx.timestamp.date()} \u2014 {dx['icd_code']}: {dx['description']}\")" }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], - "source": "# Query: get declining kidney function (eGFR < 50)\nlow_egfr = richPatient.get_events(\n event_type=\"lab\",\n filters=[\n (\"name\", \"==\", \"eGFR\"),\n (\"value\", \"<\", 50.0),\n ]\n)\nprint(\"eGFR readings below 50 (worrisome kidney function):\")\nfor lab in low_egfr:\n print(f\" {lab.timestamp.date()} — eGFR: {lab['value']} {lab['unit']}\")" + "source": "# Query: get declining kidney function (eGFR < 50)\nlow_egfr = richPatient.get_events(\n event_type=\"lab\",\n filters=[\n (\"name\", \"==\", \"eGFR\"),\n (\"value\", \"<\", 50.0),\n ]\n)\nprint(\"eGFR readings below 50 (worrisome kidney function):\")\nfor lab in low_egfr:\n print(f\" {lab.timestamp.date()} \u2014 eGFR: {lab['value']} {lab['unit']}\")" }, { "cell_type": "markdown", "id": "26be2c24", - "source": "---\n## Summary\n\n| Concept | Key API |\n|---------|----------|\n| Create an event | `Event(event_type, timestamp, **kwargs)` |\n| Access event attribute | `event[\"key\"]`, `event.key`, `\"key\" in event` |\n| Build from raw dict | `Event.from_dict(dict)` |\n| Create a patient | `Patient(patient_id, data_source=pl.DataFrame(...))` |\n| Get all events | `patient.get_events()` |\n| Filter by type | `patient.get_events(event_type=\"diagnoses_icd\")` |\n| Filter by time | `patient.get_events(start=..., end=...)` |\n| Filter by attribute | `patient.get_events(event_type=\"prescriptions\", filters=[(\"route\", \"==\", \"IV\")])` |\n| Return as DataFrame | `patient.get_events(return_df=True)` |\n| Load from MIMIC-III | `MIMIC3Dataset(root=..., tables=[\"diagnoses_icd\", ...])` |\n\n### Table name = event type\n\nWhen using a dataset loader like `MIMIC3Dataset`, the `event_type` on every event equals the **table name** from `mimic3.yaml` — not a generic category like `\"diagnosis\"`. The available attributes on each event are exactly the columns listed under that table's `attributes` key in the YAML.\n\n```\nTable name → event_type → example attributes\n─────────────────────────────────────────────────────────────────\ndiagnoses_icd → \"diagnoses_icd\" → icd9_code, hadm_id, seq_num\nprescriptions → \"prescriptions\" → drug, ndc, dose_val_rx, route\nnoteevents → \"noteevents\" → text, category, description\nadmissions → \"admissions\" → hadm_id, admission_type, hospital_expire_flag\nicustays → \"icustays\" → icustay_id, first_careunit, outtime\n```\n\nWhen writing a custom task, always check the relevant YAML config to know the exact attribute names available on events from each table.", + "source": "---\n## Part 5: Bridging to a Real Dataset\n\n| Concept | Key API |\n|---------|----------|\n| Create an event | `Event(event_type, timestamp, **kwargs)` |\n| Access event attribute | `event[\"key\"]`, `event.key`, `\"key\" in event` |\n| Build from raw dict | `Event.from_dict(dict)` |\n| Create a patient | `Patient(patient_id, data_source=pl.DataFrame(...))` |\n| Get all events | `patient.get_events()` |\n| Filter by type | `patient.get_events(event_type=\"diagnoses_icd\")` |\n| Filter by time | `patient.get_events(start=..., end=...)` |\n| Filter by attribute | `patient.get_events(event_type=\"prescriptions\", filters=[(\"route\", \"==\", \"IV\")])` |\n| Return as DataFrame | `patient.get_events(return_df=True)` |\n| Load from MIMIC-III | `MIMIC3Dataset(root=..., tables=[\"diagnoses_icd\", ...])` |\n\n### Table name = event type\n\nWhen using a dataset loader like `MIMIC3Dataset`, the `event_type` on every event equals the **table name** from `mimic3.yaml` \u2014 not a generic category like `\"diagnosis\"`. The available attributes on each event are exactly the columns listed under that table's `attributes` key in the YAML.\n\n```\nTable name \u2192 event_type \u2192 example attributes\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\ndiagnoses_icd \u2192 \"diagnoses_icd\" \u2192 icd9_code, hadm_id, seq_num\nprescriptions \u2192 \"prescriptions\" \u2192 drug, ndc, dose_val_rx, route\nnoteevents \u2192 \"noteevents\" \u2192 text, category, description\nadmissions \u2192 \"admissions\" \u2192 hadm_id, admission_type, hospital_expire_flag\nicustays \u2192 \"icustays\" \u2192 icustay_id, first_careunit, outtime\n```\n\nWhen writing a custom task, always check the relevant YAML config to know the exact attribute names available on events from each table.", "metadata": {} }, { @@ -176,7 +183,7 @@ { "cell_type": "code", "id": "65a34af1", - "source": "# Pull diagnosis events — event_type matches the table name exactly: \"diagnoses_icd\"\ndiagnoses = patient.get_events(\"diagnoses_icd\")\nprint(f\"Diagnosis events: {len(diagnoses)}\")\nprint()\n\n# Each event's attributes come from the 'attributes' list in mimic3.yaml\n# hadm_id, icd9_code, seq_num\nfor dx in diagnoses[:5]:\n print(f\" [{dx.timestamp.date()}] hadm={dx['hadm_id']} \"\n f\"ICD-9={dx['icd9_code']} seq={dx['seq_num']}\")", + "source": "# Pull diagnosis events \u2014 event_type matches the table name exactly: \"diagnoses_icd\"\ndiagnoses = patient.get_events(\"diagnoses_icd\")\nprint(f\"Diagnosis events: {len(diagnoses)}\")\nprint()\n\n# Each event's attributes come from the 'attributes' list in mimic3.yaml\n# hadm_id, icd9_code, seq_num\nfor dx in diagnoses[:5]:\n print(f\" [{dx.timestamp.date()}] hadm={dx['hadm_id']} \"\n f\"ICD-9={dx['icd9_code']} seq={dx['seq_num']}\")", "metadata": {}, "execution_count": null, "outputs": [] @@ -192,7 +199,7 @@ { "cell_type": "code", "id": "8892105c", - "source": "# Clinical note events — attribute 'text' holds the full note body\n# Attributes available: text, category, description, hadm_id, storetime (from mimic3.yaml)\nnotes = patient.get_events(\"noteevents\")\nprint(f\"Note events: {len(notes)}\")\n\ndischarge_notes = patient.get_events(\n event_type=\"noteevents\",\n filters=[(\"category\", \"==\", \"Discharge summary\")],\n)\nprint(f\"Discharge summaries: {len(discharge_notes)}\")\nif discharge_notes:\n first_note = discharge_notes[0]\n print(f\"\\n Date: {first_note.timestamp.date()}\")\n print(f\" Category: {first_note['category']}\")\n print(f\" Text preview: {str(first_note['text'])[:200]}...\")", + "source": "# Clinical note events \u2014 attribute 'text' holds the full note body\n# Attributes available: text, category, description, hadm_id, storetime (from mimic3.yaml)\nnotes = patient.get_events(\"noteevents\")\nprint(f\"Note events: {len(notes)}\")\n\ndischarge_notes = patient.get_events(\n event_type=\"noteevents\",\n filters=[(\"category\", \"==\", \"Discharge summary\")],\n)\nprint(f\"Discharge summaries: {len(discharge_notes)}\")\nif discharge_notes:\n first_note = discharge_notes[0]\n print(f\"\\n Date: {first_note.timestamp.date()}\")\n print(f\" Category: {first_note['category']}\")\n print(f\" Text preview: {str(first_note['text'])[:200]}...\")", "metadata": {}, "execution_count": null, "outputs": [] @@ -200,7 +207,7 @@ { "cell_type": "markdown", "metadata": {}, - "source": "---\n## Summary\n\n| Concept | Key API |\n|---------|----------|\n| Create an event | `Event(event_type, timestamp, **kwargs)` |\n| Access event attribute | `event[\"key\"]`, `event.key`, `\"key\" in event` |\n| Build from raw dict | `Event.from_dict(dict)` |\n| Create a patient | `Patient(patient_id, data_source=pl.DataFrame(...))` |\n| Get all events | `patient.get_events()` |\n| Filter by type | `patient.get_events(event_type=\"lab\")` |\n| Filter by time | `patient.get_events(start=..., end=...)` |\n| Filter by attribute | `patient.get_events(event_type=\"lab\", filters=[(\"value\", \">\", 7.0)])` |\n| Return as DataFrame | `patient.get_events(return_df=True)` |\n\nIn practice you won't create `Patient` objects manually — `MIMIC3Dataset` and other dataset loaders build them from raw EHR tables and expose them through the `set_task()` pipeline. But understanding the underlying API helps when writing custom tasks or debugging." + "source": "---\n## Summary\n\n| Concept | Key API |\n|---------|----------|\n| Create an event | `Event(event_type, timestamp, **kwargs)` |\n| Access event attribute | `event[\"key\"]`, `event.key`, `\"key\" in event` |\n| Build from raw dict | `Event.from_dict(dict)` |\n| Create a patient | `Patient(patient_id, data_source=pl.DataFrame(...))` |\n| Get all events | `patient.get_events()` |\n| Filter by type | `patient.get_events(event_type=\"lab\")` |\n| Filter by time | `patient.get_events(start=..., end=...)` |\n| Filter by attribute | `patient.get_events(event_type=\"lab\", filters=[(\"value\", \">\", 7.0)])` |\n| Return as DataFrame | `patient.get_events(return_df=True)` |\n\nIn practice you won't create `Patient` objects manually \u2014 `MIMIC3Dataset` and other dataset loaders build them from raw EHR tables and expose them through the `set_task()` pipeline. But understanding the underlying API helps when writing custom tasks or debugging." } ], "metadata": { diff --git a/examples/tutorials/tutorial_pyhealth_medcode.ipynb b/examples/tutorials/tutorial_pyhealth_medcode.ipynb index 04c545f10..07a8cad8b 100644 --- a/examples/tutorials/tutorial_pyhealth_medcode.ipynb +++ b/examples/tutorials/tutorial_pyhealth_medcode.ipynb @@ -3,7 +3,14 @@ { "cell_type": "markdown", "metadata": {}, - "source": "# PyHealth Medical Code Ontology Tutorial\n\nThis notebook covers **`pyhealth.medcode`** — a medical code ontology library for looking up codes, exploring hierarchies, and translating between code systems.\n\nYou will learn:\n- How to load a medical code system using **`InnerMap`**\n- How to look up diabetes codes in **ICD-10-CM** with detailed explanations\n- How to traverse the **code hierarchy** (ancestors and descendants)\n- How to **translate codes** between systems using **`CrossMap`** (e.g., ICD-9 → ICD-10, ICD-10 → CCS)\n- Practical patterns for preprocessing EHR datasets\n\n---" + "source": "# PyHealth Medical Code Ontology Tutorial\n\nThis notebook covers **`pyhealth.medcode`** \u2014 a medical code ontology library for looking up codes, exploring hierarchies, and translating between code systems.\n\nYou will learn:\n- How to load a medical code system using **`InnerMap`**\n- How to look up diabetes codes in **ICD-10-CM** with detailed explanations\n- How to traverse the **code hierarchy** (ancestors and descendants)\n- How to **translate codes** between systems using **`CrossMap`** (e.g., ICD-9 \u2192 ICD-10, ICD-10 \u2192 CCS)\n- Practical patterns for preprocessing EHR datasets\n\n---" + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": "!pip install pyhealth" }, { "cell_type": "code", @@ -15,7 +22,7 @@ { "cell_type": "markdown", "metadata": {}, - "source": "---\n## Background: Medical Code Systems\n\nEHR data uses several overlapping code systems:\n\n| System | Domain | Example |\n|--------|--------|----------|\n| **ICD-10-CM** | Diagnoses (current US standard) | `E11.9` = Type 2 DM |\n| **ICD-9-CM** | Diagnoses (legacy, pre-2015) | `250.00` = Type 2 DM |\n| **ICD-10-PCS / ICD-9-PROC** | Procedures | |\n| **ATC** | Drug classification hierarchy | `A10BA02` = Metformin |\n| **RxNorm** | Drug concepts (US) | `860975` = Metformin 500mg tablet |\n| **NDC** | Drug product codes (package level) | |\n| **CCSCM** | Clinical Classifications Software — Diagnoses | `49` = Diabetes mellitus |\n| **CCSPROC** | CCS — Procedures | |\n\n**Why code mapping matters in ML:**\n- MIMIC-III uses ICD-9 codes (pre-2015 data), while MIMIC-IV uses ICD-10\n- Vocabularies differ in specificity: ICD-10 has ~70,000 codes vs ICD-9's ~14,000\n- ML models trained on ICD-9 codes cannot directly generalize to ICD-10 datasets without mapping\n- CCS groups 70,000 ICD-10 codes into ~300 categories — much better for small datasets" + "source": "---\n## Background: Medical Code Systems\n\nEHR data uses several overlapping code systems:\n\n| System | Domain | Example |\n|--------|--------|----------|\n| **ICD-10-CM** | Diagnoses (current US standard) | `E11.9` = Type 2 DM |\n| **ICD-9-CM** | Diagnoses (legacy, pre-2015) | `250.00` = Type 2 DM |\n| **ICD-10-PCS / ICD-9-PROC** | Procedures | |\n| **ATC** | Drug classification hierarchy | `A10BA02` = Metformin |\n| **RxNorm** | Drug concepts (US) | `860975` = Metformin 500mg tablet |\n| **NDC** | Drug product codes (package level) | |\n| **CCSCM** | Clinical Classifications Software \u2014 Diagnoses | `49` = Diabetes mellitus |\n| **CCSPROC** | CCS \u2014 Procedures | |\n\n**Why code mapping matters in ML:**\n- MIMIC-III uses ICD-9 codes (pre-2015 data), while MIMIC-IV uses ICD-10\n- Vocabularies differ in specificity: ICD-10 has ~70,000 codes vs ICD-9's ~14,000\n- ML models trained on ICD-9 codes cannot directly generalize to ICD-10 datasets without mapping\n- CCS groups 70,000 ICD-10 codes into ~300 categories \u2014 much better for small datasets" }, { "cell_type": "markdown", @@ -27,7 +34,7 @@ "execution_count": null, "metadata": {}, "outputs": [], - "source": "# Load ICD-10-CM (Clinical Modification) — the US standard for diagnosis codes\nicd10cm = InnerMap.load(\"ICD10CM\")\n\n# Print statistics\nicd10cm.stat()" + "source": "# Load ICD-10-CM (Clinical Modification) \u2014 the US standard for diagnosis codes\nicd10cm = InnerMap.load(\"ICD10CM\")\n\n# Print statistics\nicd10cm.stat()" }, { "cell_type": "code", @@ -46,7 +53,7 @@ { "cell_type": "markdown", "metadata": {}, - "source": "---\n## Part 2: Diabetes Code Deep Dive\n\nDiabetes mellitus is encoded in ICD-10-CM chapter E08–E13. Here's the full taxonomy:\n\n```\nE08 Diabetes mellitus due to underlying condition\nE09 Drug or chemical induced diabetes mellitus\nE10 Type 1 diabetes mellitus\nE11 Type 2 diabetes mellitus\nE13 Other specified diabetes mellitus\n```\n\nEach category expands into complication subtypes. The E11 (Type 2) branch has **87 billable codes** in 2026 ICD-10-CM — a testament to how granular modern clinical coding is:\n\n```\nE11 Type 2 DM\n├─ E11.00 / E11.01 with hyperosmolarity (without / with coma)\n├─ E11.10 / E11.11 with ketoacidosis (without / with coma)\n├─ E11.2 with kidney complications\n│ ├─ E11.21 with diabetic nephropathy\n│ └─ E11.22 with diabetic chronic kidney disease\n├─ E11.3 with ophthalmic complications\n│ ├─ E11.311 / E11.319 unspecified retinopathy (with / without macular edema)\n│ ├─ E11.321x–E11.359x nonproliferative/proliferative retinopathy\n│ │ (each further split: right eye / left eye / bilateral / unspecified)\n│ └─ E11.36 with diabetic cataract\n├─ E11.4 with neurological complications\n│ ├─ E11.40 with diabetic neuropathy, unspecified\n│ └─ E11.42 with diabetic polyneuropathy\n├─ E11.5 with circulatory complications\n│ ├─ E11.51 with peripheral angiopathy without gangrene\n│ └─ E11.52 with peripheral angiopathy with gangrene\n├─ E11.6 with other specified complications\n│ ├─ E11.65 with hyperglycemia\n│ └─ E11.69 with other specified complication\n├─ E11.8 with unspecified complications\n├─ E11.9 without complications (most common at initial diagnosis)\n└─ E11.A without complications, in remission ← NEW in FY2026\n```\n\n> **2026 addition — `E11.A`:** *\"Type 2 diabetes mellitus without complications in remission\"* — confirmed valid for HIPAA transactions in the FY2026 ICD-10-CM release. This distinguishes patients who have achieved sustained normoglycemia (remission — e.g., post-bariatric surgery or sustained lifestyle intervention) from those still actively managed (E11.9).\n\n> **Note on retinopathy codes:** The E11.3x subcategory is highly specific. Real-world MIMIC data often uses the unspecified form (`E11.319`) because the laterality (left/right/bilateral) was not recorded at the time of billing. ML models typically collapse these to the 3–4 character level (e.g., using CCS or grouping all `E11.3xx` together)." + "source": "---\n## Part 2: Diabetes Code Deep Dive\n\nDiabetes mellitus is encoded in ICD-10-CM chapter E08\u2013E13. Here's the full taxonomy:\n\n```\nE08 Diabetes mellitus due to underlying condition\nE09 Drug or chemical induced diabetes mellitus\nE10 Type 1 diabetes mellitus\nE11 Type 2 diabetes mellitus\nE13 Other specified diabetes mellitus\n```\n\nEach category expands into complication subtypes. The E11 (Type 2) branch has **87 billable codes** in 2026 ICD-10-CM \u2014 a testament to how granular modern clinical coding is:\n\n```\nE11 Type 2 DM\n\u251c\u2500 E11.00 / E11.01 with hyperosmolarity (without / with coma)\n\u251c\u2500 E11.10 / E11.11 with ketoacidosis (without / with coma)\n\u251c\u2500 E11.2 with kidney complications\n\u2502 \u251c\u2500 E11.21 with diabetic nephropathy\n\u2502 \u2514\u2500 E11.22 with diabetic chronic kidney disease\n\u251c\u2500 E11.3 with ophthalmic complications\n\u2502 \u251c\u2500 E11.311 / E11.319 unspecified retinopathy (with / without macular edema)\n\u2502 \u251c\u2500 E11.321x\u2013E11.359x nonproliferative/proliferative retinopathy\n\u2502 \u2502 (each further split: right eye / left eye / bilateral / unspecified)\n\u2502 \u2514\u2500 E11.36 with diabetic cataract\n\u251c\u2500 E11.4 with neurological complications\n\u2502 \u251c\u2500 E11.40 with diabetic neuropathy, unspecified\n\u2502 \u2514\u2500 E11.42 with diabetic polyneuropathy\n\u251c\u2500 E11.5 with circulatory complications\n\u2502 \u251c\u2500 E11.51 with peripheral angiopathy without gangrene\n\u2502 \u2514\u2500 E11.52 with peripheral angiopathy with gangrene\n\u251c\u2500 E11.6 with other specified complications\n\u2502 \u251c\u2500 E11.65 with hyperglycemia\n\u2502 \u2514\u2500 E11.69 with other specified complication\n\u251c\u2500 E11.8 with unspecified complications\n\u251c\u2500 E11.9 without complications (most common at initial diagnosis)\n\u2514\u2500 E11.A without complications, in remission \u2190 NEW in FY2026\n```\n\n> **2026 addition \u2014 `E11.A`:** *\"Type 2 diabetes mellitus without complications in remission\"* \u2014 confirmed valid for HIPAA transactions in the FY2026 ICD-10-CM release. This distinguishes patients who have achieved sustained normoglycemia (remission \u2014 e.g., post-bariatric surgery or sustained lifestyle intervention) from those still actively managed (E11.9).\n\n> **Note on retinopathy codes:** The E11.3x subcategory is highly specific. Real-world MIMIC data often uses the unspecified form (`E11.319`) because the laterality (left/right/bilateral) was not recorded at the time of billing. ML models typically collapse these to the 3\u20134 character level (e.g., using CCS or grouping all `E11.3xx` together)." }, { "cell_type": "code", @@ -74,26 +81,26 @@ "execution_count": null, "metadata": {}, "outputs": [], - "source": "# --- 2026 New Code: E11.A ---\n# Confirmed valid for HIPAA transactions in FY2026 ICD-10-CM (verified against live 2026 dataset).\n# Official description: \"Type 2 diabetes mellitus without complications in remission\"\n#\n# Clinical context:\n# E11.9 = T2DM without complications (still being managed / monitored)\n# E11.A = T2DM without complications IN REMISSION (achieved normoglycemia)\n#\n# Remission criteria (ADA 2021 Consensus): HbA1c < 6.5% for at least 3 months\n# without the use of glucose-lowering pharmacotherapy.\n# Common after bariatric surgery or significant sustained lifestyle intervention.\n\nnew_2026_code = \"E11.A\"\nif new_2026_code in icd10cm:\n name = icd10cm.lookup(new_2026_code)\n print(f\"[{new_2026_code}] {name}\")\n print()\n print(\"Contrast with E11.9:\")\n print(f\" [E11.9 ] {icd10cm.lookup('E11.9')}\")\n print(f\" [E11.A ] {name}\")\n print()\n print(\"Clinical significance:\")\n print(\" E11.9 → patient still has diabetes, actively managed\")\n print(\" E11.A → patient has achieved remission (ADA criteria: HbA1c < 6.5% for ≥3 months,\")\n print(\" no glucose-lowering medication)\")\nelse:\n # Fallback if the PyHealth cache predates FY2026\n print(\"E11.A not yet in local ICD10CM cache.\")\n print(\"Official 2026 description: 'Type 2 diabetes mellitus without complications in remission'\")\n print(\"Update the cache with: InnerMap.load('ICD10CM', refresh_cache=True)\")" + "source": "# --- 2026 New Code: E11.A ---\n# Confirmed valid for HIPAA transactions in FY2026 ICD-10-CM (verified against live 2026 dataset).\n# Official description: \"Type 2 diabetes mellitus without complications in remission\"\n#\n# Clinical context:\n# E11.9 = T2DM without complications (still being managed / monitored)\n# E11.A = T2DM without complications IN REMISSION (achieved normoglycemia)\n#\n# Remission criteria (ADA 2021 Consensus): HbA1c < 6.5% for at least 3 months\n# without the use of glucose-lowering pharmacotherapy.\n# Common after bariatric surgery or significant sustained lifestyle intervention.\n\nnew_2026_code = \"E11.A\"\nif new_2026_code in icd10cm:\n name = icd10cm.lookup(new_2026_code)\n print(f\"[{new_2026_code}] {name}\")\n print()\n print(\"Contrast with E11.9:\")\n print(f\" [E11.9 ] {icd10cm.lookup('E11.9')}\")\n print(f\" [E11.A ] {name}\")\n print()\n print(\"Clinical significance:\")\n print(\" E11.9 \u2192 patient still has diabetes, actively managed\")\n print(\" E11.A \u2192 patient has achieved remission (ADA criteria: HbA1c < 6.5% for \u22653 months,\")\n print(\" no glucose-lowering medication)\")\nelse:\n # Fallback if the PyHealth cache predates FY2026\n print(\"E11.A not yet in local ICD10CM cache.\")\n print(\"Official 2026 description: 'Type 2 diabetes mellitus without complications in remission'\")\n print(\"Update the cache with: InnerMap.load('ICD10CM', refresh_cache=True)\")" }, { "cell_type": "markdown", "metadata": {}, - "source": "---\n## Part 3: Hierarchy Exploration\n\nICD codes form a tree where more specific codes are children of broader parent codes. PyHealth exposes this hierarchy via:\n- `get_ancestors(code)` — returns parent codes, ordered from closest to farthest\n- `get_descendants(code)` — returns child codes, ordered from closest to farthest\n\nThis hierarchy is stored internally as a **directed graph** using NetworkX." + "source": "---\n## Part 3: Hierarchy Exploration\n\nICD codes form a tree where more specific codes are children of broader parent codes. PyHealth exposes this hierarchy via:\n- `get_ancestors(code)` \u2014 returns parent codes, ordered from closest to farthest\n- `get_descendants(code)` \u2014 returns child codes, ordered from closest to farthest\n\nThis hierarchy is stored internally as a **directed graph** using NetworkX." }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], - "source": "# --- Ancestor lookup: trace E11.22 up the hierarchy ---\n# E11.22 = Type 2 diabetes mellitus with diabetic chronic kidney disease\ncode = \"E11.22\"\nancestors = icd10cm.get_ancestors(code)\n\nprint(f\"Ancestors of {code} ({icd10cm.lookup(code) if code in icd10cm else 'T2DM with CKD'}):\")\nprint(f\" [{code}] (starting code)\")\nfor anc in ancestors:\n if anc in icd10cm:\n name = icd10cm.lookup(anc)\n print(f\" ↑ [{anc}] {name}\")\n else:\n print(f\" ↑ [{anc}] (category node)\")" + "source": "# --- Ancestor lookup: trace E11.22 up the hierarchy ---\n# E11.22 = Type 2 diabetes mellitus with diabetic chronic kidney disease\ncode = \"E11.22\"\nancestors = icd10cm.get_ancestors(code)\n\nprint(f\"Ancestors of {code} ({icd10cm.lookup(code) if code in icd10cm else 'T2DM with CKD'}):\")\nprint(f\" [{code}] (starting code)\")\nfor anc in ancestors:\n if anc in icd10cm:\n name = icd10cm.lookup(anc)\n print(f\" \u2191 [{anc}] {name}\")\n else:\n print(f\" \u2191 [{anc}] (category node)\")" }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], - "source": "# --- Descendant lookup: find all Type 2 DM subtypes ---\n# The live 2026 ICD-10-CM dataset has 87 billable E11 codes —\n# reflecting the high granularity of modern diabetes coding (retinopathy\n# laterality, ketoacidosis severity, complication type, etc.)\n\nparent_code = \"E11\"\ndescendants = icd10cm.get_descendants(parent_code)\n\nprint(f\"Descendants of {parent_code} (Type 2 Diabetes Mellitus):\")\nprint(f\" Total subtypes in this ICD10CM version: {len(descendants)}\")\nprint(f\" (FY2026 live dataset has 87 billable codes)\")\nprint()\n\n# Show the first 20 for readability — the full list is much longer\nprint(\"First 20 (sorted by code):\")\nfor desc in sorted(descendants)[:20]:\n if desc in icd10cm:\n name = icd10cm.lookup(desc)\n print(f\" [{desc}] {name}\")" + "source": "# --- Descendant lookup: find all Type 2 DM subtypes ---\n# The live 2026 ICD-10-CM dataset has 87 billable E11 codes \u2014\n# reflecting the high granularity of modern diabetes coding (retinopathy\n# laterality, ketoacidosis severity, complication type, etc.)\n\nparent_code = \"E11\"\ndescendants = icd10cm.get_descendants(parent_code)\n\nprint(f\"Descendants of {parent_code} (Type 2 Diabetes Mellitus):\")\nprint(f\" Total subtypes in this ICD10CM version: {len(descendants)}\")\nprint(f\" (FY2026 live dataset has 87 billable codes)\")\nprint()\n\n# Show the first 20 for readability \u2014 the full list is much longer\nprint(\"First 20 (sorted by code):\")\nfor desc in sorted(descendants)[:20]:\n if desc in icd10cm:\n name = icd10cm.lookup(desc)\n print(f\" [{desc}] {name}\")" }, { "cell_type": "code", @@ -119,21 +126,21 @@ "execution_count": null, "metadata": {}, "outputs": [], - "source": "# --- ICD-9-CM → ICD-10-CM ---\n# MIMIC-III uses ICD-9; MIMIC-IV uses ICD-10.\n# The GEM (General Equivalence Mappings) crosswalk handles this translation.\n\ncm_9to10 = CrossMap.load(\"ICD9CM\", \"ICD10CM\")\n\n# ICD-9 diabetes codes (legacy MIMIC-III style)\nicd9_diabetes = {\n \"250.00\": \"Diabetes mellitus without mention of complication, type II\",\n \"250.10\": \"Diabetes with ketoacidosis, type II\",\n \"250.40\": \"Diabetes with renal manifestations, type II\",\n \"250.60\": \"Diabetes with neurological manifestations, type II\",\n}\n\nprint(\"ICD-9-CM → ICD-10-CM Diabetes Code Mapping:\")\nprint()\nfor icd9_code, icd9_name in icd9_diabetes.items():\n icd10_codes = cm_9to10.map(icd9_code)\n print(f\" ICD-9 {icd9_code} — {icd9_name}\")\n print(f\" → ICD-10: {icd10_codes}\")\n for c in icd10_codes:\n if c in icd10cm:\n print(f\" [{c}] {icd10cm.lookup(c)}\")\n print()" + "source": "# --- ICD-9-CM \u2192 ICD-10-CM ---\n# MIMIC-III uses ICD-9; MIMIC-IV uses ICD-10.\n# The GEM (General Equivalence Mappings) crosswalk handles this translation.\n\ncm_9to10 = CrossMap.load(\"ICD9CM\", \"ICD10CM\")\n\n# ICD-9 diabetes codes (legacy MIMIC-III style)\nicd9_diabetes = {\n \"250.00\": \"Diabetes mellitus without mention of complication, type II\",\n \"250.10\": \"Diabetes with ketoacidosis, type II\",\n \"250.40\": \"Diabetes with renal manifestations, type II\",\n \"250.60\": \"Diabetes with neurological manifestations, type II\",\n}\n\nprint(\"ICD-9-CM \u2192 ICD-10-CM Diabetes Code Mapping:\")\nprint()\nfor icd9_code, icd9_name in icd9_diabetes.items():\n icd10_codes = cm_9to10.map(icd9_code)\n print(f\" ICD-9 {icd9_code} \u2014 {icd9_name}\")\n print(f\" \u2192 ICD-10: {icd10_codes}\")\n for c in icd10_codes:\n if c in icd10cm:\n print(f\" [{c}] {icd10cm.lookup(c)}\")\n print()" }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], - "source": "# --- ICD-10-CM → CCS (Clinical Classifications Software) ---\n# CCS groups ~70,000 ICD-10 codes into ~300 clinically meaningful categories.\n# CCS category 49 = \"Diabetes mellitus without complication\"\n# CCS category 50 = \"Diabetes mellitus with complications\"\n\ncm_10toCCS = CrossMap.load(\"ICD10CM\", \"CCSCM\")\n\nprint(\"ICD-10-CM → CCS Category Mapping:\")\nprint()\ntype2_sample = [\"E11.9\", \"E11.65\", \"E11.22\", \"E11.42\", \"E10.9\"]\nfor code in type2_sample:\n ccs_cats = cm_10toCCS.map(code)\n icd_name = icd10cm.lookup(code) if code in icd10cm else \"(not found)\"\n print(f\" [{code}] {icd_name}\")\n print(f\" → CCS: {ccs_cats}\")\n print()" + "source": "# --- ICD-10-CM \u2192 CCS (Clinical Classifications Software) ---\n# CCS groups ~70,000 ICD-10 codes into ~300 clinically meaningful categories.\n# CCS category 49 = \"Diabetes mellitus without complication\"\n# CCS category 50 = \"Diabetes mellitus with complications\"\n\ncm_10toCCS = CrossMap.load(\"ICD10CM\", \"CCSCM\")\n\nprint(\"ICD-10-CM \u2192 CCS Category Mapping:\")\nprint()\ntype2_sample = [\"E11.9\", \"E11.65\", \"E11.22\", \"E11.42\", \"E10.9\"]\nfor code in type2_sample:\n ccs_cats = cm_10toCCS.map(code)\n icd_name = icd10cm.lookup(code) if code in icd10cm else \"(not found)\"\n print(f\" [{code}] {icd_name}\")\n print(f\" \u2192 CCS: {ccs_cats}\")\n print()" }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], - "source": "# --- ICD-9-CM → CCS (direct, for MIMIC-III) ---\ncm_9toCCS = CrossMap.load(\"ICD9CM\", \"CCSCM\")\n\nprint(\"ICD-9-CM → CCS (useful for MIMIC-III preprocessing):\")\nprint()\nfor icd9_code in [\"250.00\", \"250.10\", \"250.40\", \"250.60\"]:\n ccs_cats = cm_9toCCS.map(icd9_code)\n print(f\" {icd9_code} → CCS: {ccs_cats}\")" + "source": "# --- ICD-9-CM \u2192 CCS (direct, for MIMIC-III) ---\ncm_9toCCS = CrossMap.load(\"ICD9CM\", \"CCSCM\")\n\nprint(\"ICD-9-CM \u2192 CCS (useful for MIMIC-III preprocessing):\")\nprint()\nfor icd9_code in [\"250.00\", \"250.10\", \"250.40\", \"250.60\"]:\n ccs_cats = cm_9toCCS.map(icd9_code)\n print(f\" {icd9_code} \u2192 CCS: {ccs_cats}\")" }, { "cell_type": "markdown", @@ -152,7 +159,7 @@ "execution_count": null, "metadata": {}, "outputs": [], - "source": "# --- ATC (Anatomical Therapeutic Chemical) for drug classification ---\n# ATC hierarchy: Level1 (organ system) → Level2 (main group) → Level3 → Level4 → Level5 (substance)\n# A10BA02 = Metformin\natc = InnerMap.load(\"ATC\")\natc.stat()\n\nmetformin_code = \"A10BA02\"\nif metformin_code in atc:\n print(f\"ATC code {metformin_code}: {atc.lookup(metformin_code)}\")\n ancestors_atc = atc.get_ancestors(metformin_code)\n print(\"Ancestors (drug class hierarchy):\")\n for anc in ancestors_atc:\n if anc in atc:\n print(f\" ↑ [{anc}] {atc.lookup(anc)}\")" + "source": "# --- ATC (Anatomical Therapeutic Chemical) for drug classification ---\n# ATC hierarchy: Level1 (organ system) \u2192 Level2 (main group) \u2192 Level3 \u2192 Level4 \u2192 Level5 (substance)\n# A10BA02 = Metformin\natc = InnerMap.load(\"ATC\")\natc.stat()\n\nmetformin_code = \"A10BA02\"\nif metformin_code in atc:\n print(f\"ATC code {metformin_code}: {atc.lookup(metformin_code)}\")\n ancestors_atc = atc.get_ancestors(metformin_code)\n print(\"Ancestors (drug class hierarchy):\")\n for anc in ancestors_atc:\n if anc in atc:\n print(f\" \u2191 [{anc}] {atc.lookup(anc)}\")" }, { "cell_type": "markdown", @@ -171,14 +178,14 @@ "execution_count": null, "metadata": {}, "outputs": [], - "source": "# Pattern 2: Translate a patient's ICD-9 code list to CCS before modeling\n# This dramatically reduces vocabulary size.\n\ndef translate_codes_to_ccs(icd9_codes, crossmap):\n \"\"\"Map a list of ICD-9 codes to CCS categories.\"\"\"\n ccs_codes = []\n for code in icd9_codes:\n mapped = crossmap.map(code)\n ccs_codes.extend(mapped)\n return list(set(ccs_codes)) # deduplicate\n\n# Example patient from MIMIC-III\npatient_icd9_codes = [\"250.00\", \"401.9\", \"428.0\", \"585.3\"]\n# = Type 2 DM, Essential hypertension, Heart failure, CKD stage 3\n\npatient_ccs_codes = translate_codes_to_ccs(patient_icd9_codes, cm_9toCCS)\nprint(\"ICD-9 codes:\", patient_icd9_codes)\nprint(\"CCS codes: \", patient_ccs_codes)\nprint(f\"Vocabulary reduction: {len(icd9cm.graph.nodes)} ICD-9 codes → ~300 CCS categories\")" + "source": "# Pattern 2: Translate a patient's ICD-9 code list to CCS before modeling\n# This dramatically reduces vocabulary size.\n\ndef translate_codes_to_ccs(icd9_codes, crossmap):\n \"\"\"Map a list of ICD-9 codes to CCS categories.\"\"\"\n ccs_codes = []\n for code in icd9_codes:\n mapped = crossmap.map(code)\n ccs_codes.extend(mapped)\n return list(set(ccs_codes)) # deduplicate\n\n# Example patient from MIMIC-III\npatient_icd9_codes = [\"250.00\", \"401.9\", \"428.0\", \"585.3\"]\n# = Type 2 DM, Essential hypertension, Heart failure, CKD stage 3\n\npatient_ccs_codes = translate_codes_to_ccs(patient_icd9_codes, cm_9toCCS)\nprint(\"ICD-9 codes:\", patient_icd9_codes)\nprint(\"CCS codes: \", patient_ccs_codes)\nprint(f\"Vocabulary reduction: {len(icd9cm.graph.nodes)} ICD-9 codes \u2192 ~300 CCS categories\")" }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], - "source": "# Pattern 3: Code validation — remove invalid/unknown codes before training\n# Real EHR data often contains typos, deprecated codes, and free-text entries.\n\nraw_codes_from_ehr = [\"E11.9\", \"E11.99\", \"DIAB\", \"E11.65\", \"999.999\", \"E10.9\"]\nvalid_codes = [c for c in raw_codes_from_ehr if c in icd10cm]\ninvalid_codes = [c for c in raw_codes_from_ehr if c not in icd10cm]\n\nprint(\"Raw codes from EHR:\", raw_codes_from_ehr)\nprint(\"Valid ICD-10-CM codes:\", valid_codes)\nprint(\"Invalid / unknown codes:\", invalid_codes)" + "source": "# Pattern 3: Code validation \u2014 remove invalid/unknown codes before training\n# Real EHR data often contains typos, deprecated codes, and free-text entries.\n\nraw_codes_from_ehr = [\"E11.9\", \"E11.99\", \"DIAB\", \"E11.65\", \"999.999\", \"E10.9\"]\nvalid_codes = [c for c in raw_codes_from_ehr if c in icd10cm]\ninvalid_codes = [c for c in raw_codes_from_ehr if c not in icd10cm]\n\nprint(\"Raw codes from EHR:\", raw_codes_from_ehr)\nprint(\"Valid ICD-10-CM codes:\", valid_codes)\nprint(\"Invalid / unknown codes:\", invalid_codes)" }, { "cell_type": "markdown", diff --git a/examples/tutorials/tutorial_pyhealth_metrics.ipynb b/examples/tutorials/tutorial_pyhealth_metrics.ipynb index bbb5ba657..263d3bf34 100644 --- a/examples/tutorials/tutorial_pyhealth_metrics.ipynb +++ b/examples/tutorials/tutorial_pyhealth_metrics.ipynb @@ -3,7 +3,14 @@ { "cell_type": "markdown", "metadata": {}, - "source": "# PyHealth Metrics Tutorial\n\nThis notebook covers **`pyhealth.metrics`** — a collection of evaluation functions for clinical prediction tasks.\n\nYou will learn:\n- **Binary classification** metrics: AUC-ROC, AUC-PR, F1, ECE, and more\n- **Multiclass classification** metrics: accuracy, macro/micro F1\n- **Multilabel classification** metrics: hamming loss, sample-level AUC\n- **Fairness metrics**: disparate impact and statistical parity difference\n- How to call `trainer.inference()` to get raw predictions for custom evaluation\n\n> **Design note:** All metric functions in PyHealth accept raw numpy arrays, so they can be used independently of the Trainer or with any ML framework.\n\n---" + "source": "# PyHealth Metrics Tutorial\n\nThis notebook covers **`pyhealth.metrics`** \u2014 a collection of evaluation functions for clinical prediction tasks.\n\nYou will learn:\n- **Binary classification** metrics: AUC-ROC, AUC-PR, F1, ECE, and more\n- **Multiclass classification** metrics: accuracy, macro/micro F1\n- **Multilabel classification** metrics: hamming loss, sample-level AUC\n- **Fairness metrics**: disparate impact and statistical parity difference\n- How to call `trainer.inference()` to get raw predictions for custom evaluation\n\n> **Design note:** All metric functions in PyHealth accept raw numpy arrays, so they can be used independently of the Trainer or with any ML framework.\n\n---" + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": "!pip install pyhealth" }, { "cell_type": "code", @@ -15,7 +22,7 @@ { "cell_type": "markdown", "metadata": {}, - "source": "---\n## Part 1: Binary Classification Metrics\n\nBinary classification is the most common setup in clinical prediction:\n- In-hospital mortality (alive / deceased)\n- Readmission within 30 days (yes / no)\n- Disease onset (positive / negative)\n\n```python\nbinary_metrics_fn(\n y_true: np.ndarray, # shape (n_samples,), values in {0, 1}\n y_prob: np.ndarray, # shape (n_samples,), values in [0, 1]\n metrics: Optional[List[str]] = None, # default: [\"pr_auc\", \"roc_auc\", \"f1\"]\n threshold: float = 0.5, # decision boundary for accuracy/F1/etc.\n)\n```\n\n### Supported metrics\n\n| Metric | Description |\n|--------|-------------|\n| `roc_auc` | Area under ROC curve — threshold-free measure of discrimination |\n| `pr_auc` | Area under Precision-Recall curve — better for imbalanced datasets |\n| `f1` | Harmonic mean of precision and recall |\n| `accuracy` | Fraction of correct predictions |\n| `balanced_accuracy` | Accuracy adjusted for class imbalance |\n| `precision` | TP / (TP + FP) |\n| `recall` | TP / (TP + FN) |\n| `cohen_kappa` | Agreement beyond chance |\n| `jaccard` | Intersection over union for positive class |\n| `ECE` | Expected Calibration Error (calibration quality) |\n| `ECE_adapt` | Adaptive ECE (equal-mass bins) |" + "source": "---\n## Part 1: Binary Classification Metrics\n\nBinary classification is the most common setup in clinical prediction:\n- In-hospital mortality (alive / deceased)\n- Readmission within 30 days (yes / no)\n- Disease onset (positive / negative)\n\n```python\nbinary_metrics_fn(\n y_true: np.ndarray, # shape (n_samples,), values in {0, 1}\n y_prob: np.ndarray, # shape (n_samples,), values in [0, 1]\n metrics: Optional[List[str]] = None, # default: [\"pr_auc\", \"roc_auc\", \"f1\"]\n threshold: float = 0.5, # decision boundary for accuracy/F1/etc.\n)\n```\n\n### Supported metrics\n\n| Metric | Description |\n|--------|-------------|\n| `roc_auc` | Area under ROC curve \u2014 threshold-free measure of discrimination |\n| `pr_auc` | Area under Precision-Recall curve \u2014 better for imbalanced datasets |\n| `f1` | Harmonic mean of precision and recall |\n| `accuracy` | Fraction of correct predictions |\n| `balanced_accuracy` | Accuracy adjusted for class imbalance |\n| `precision` | TP / (TP + FP) |\n| `recall` | TP / (TP + FN) |\n| `cohen_kappa` | Agreement beyond chance |\n| `jaccard` | Intersection over union for positive class |\n| `ECE` | Expected Calibration Error (calibration quality) |\n| `ECE_adapt` | Adaptive ECE (equal-mass bins) |" }, { "cell_type": "code", @@ -53,7 +60,7 @@ { "cell_type": "markdown", "metadata": {}, - "source": "---\n## Part 2: Multiclass Classification Metrics\n\nMulticlass is used when predicting among 3+ mutually exclusive outcomes, for example:\n- Primary discharge diagnosis category (e.g., CCS groups)\n- Length-of-stay bucket (short / medium / long)\n- Triage acuity level (1–5)\n\n```python\nmulticlass_metrics_fn(\n y_true: np.ndarray, # shape (n_samples,), integer class indices\n y_prob: np.ndarray, # shape (n_samples, num_classes), sum to 1\n metrics: Optional[List[str]] = None, # default: [\"accuracy\", \"f1_macro\", \"f1_micro\"]\n)\n```\n\n### Macro vs Micro averaging\n\n| Averaging | Computes | Best for |\n|-----------|----------|----------|\n| `macro` | Mean of per-class metric | When all classes are equally important |\n| `micro` | Global TP/FP/FN counts | When overall performance matters more than per-class balance |\n| `weighted` | Weighted by class support | When you want to account for class frequency |" + "source": "---\n## Part 2: Multiclass Classification Metrics\n\nMulticlass is used when predicting among 3+ mutually exclusive outcomes, for example:\n- Primary discharge diagnosis category (e.g., CCS groups)\n- Length-of-stay bucket (short / medium / long)\n- Triage acuity level (1\u20135)\n\n```python\nmulticlass_metrics_fn(\n y_true: np.ndarray, # shape (n_samples,), integer class indices\n y_prob: np.ndarray, # shape (n_samples, num_classes), sum to 1\n metrics: Optional[List[str]] = None, # default: [\"accuracy\", \"f1_macro\", \"f1_micro\"]\n)\n```\n\n### Macro vs Micro averaging\n\n| Averaging | Computes | Best for |\n|-----------|----------|----------|\n| `macro` | Mean of per-class metric | When all classes are equally important |\n| `micro` | Global TP/FP/FN counts | When overall performance matters more than per-class balance |\n| `weighted` | Weighted by class support | When you want to account for class frequency |" }, { "cell_type": "code", @@ -105,19 +112,19 @@ { "cell_type": "markdown", "metadata": {}, - "source": "### Interpreting multilabel metrics\n\n| Metric | Clinical interpretation |\n|--------|------------------------|\n| `pr_auc_samples` | How well the model ranks drugs for each patient — the primary metric for drug recommendation |\n| `hamming_loss` | Fraction of all (patient, drug) pairs incorrectly classified — penalizes false positives equally |\n| `accuracy` (exact match) | Very strict — 1 only if all drugs are exactly correct |\n| `f1_macro` | Per-drug average F1 — gives equal weight to rare and common drugs |" + "source": "### Interpreting multilabel metrics\n\n| Metric | Clinical interpretation |\n|--------|------------------------|\n| `pr_auc_samples` | How well the model ranks drugs for each patient \u2014 the primary metric for drug recommendation |\n| `hamming_loss` | Fraction of all (patient, drug) pairs incorrectly classified \u2014 penalizes false positives equally |\n| `accuracy` (exact match) | Very strict \u2014 1 only if all drugs are exactly correct |\n| `f1_macro` | Per-drug average F1 \u2014 gives equal weight to rare and common drugs |" }, { "cell_type": "markdown", "metadata": {}, - "source": "---\n## Part 4: Fairness Metrics\n\nFairness metrics assess whether a model's performance is **equitable across subgroups** defined by sensitive attributes (e.g., race, sex, age group). This is crucial in clinical AI to avoid perpetuating historical health disparities.\n\n```python\nfairness_metrics_fn(\n y_true: np.ndarray, # (n_samples,) true labels\n y_prob: np.ndarray, # (n_samples,) predicted probabilities\n sensitive_attributes: np.ndarray, # (n_samples,) 1=protected group, 0=unprotected\n favorable_outcome: int = 1, # which label value is considered positive\n metrics: Optional[List[str]] = None, # default: both below\n threshold: float = 0.5,\n)\n```\n\n### Supported fairness metrics\n\n| Metric | Formula | Interpretation |\n|--------|---------|----------------|\n| `disparate_impact` | P(ŷ=1 | protected) / P(ŷ=1 | unprotected) | Should be ≥ 0.8 (80% rule). 1.0 = perfect parity |\n| `statistical_parity_difference` | P(ŷ=1 | protected) − P(ŷ=1 | unprotected) | Should be close to 0. Negative = protected group predicted positive less often |" + "source": "---\n## Part 4: Fairness Metrics\n\nFairness metrics assess whether a model's performance is **equitable across subgroups** defined by sensitive attributes (e.g., race, sex, age group). This is crucial in clinical AI to avoid perpetuating historical health disparities.\n\n```python\nfairness_metrics_fn(\n y_true: np.ndarray, # (n_samples,) true labels\n y_prob: np.ndarray, # (n_samples,) predicted probabilities\n sensitive_attributes: np.ndarray, # (n_samples,) 1=protected group, 0=unprotected\n favorable_outcome: int = 1, # which label value is considered positive\n metrics: Optional[List[str]] = None, # default: both below\n threshold: float = 0.5,\n)\n```\n\n### Supported fairness metrics\n\n| Metric | Formula | Interpretation |\n|--------|---------|----------------|\n| `disparate_impact` | P(\u0177=1 | protected) / P(\u0177=1 | unprotected) | Should be \u2265 0.8 (80% rule). 1.0 = perfect parity |\n| `statistical_parity_difference` | P(\u0177=1 | protected) \u2212 P(\u0177=1 | unprotected) | Should be close to 0. Negative = protected group predicted positive less often |" }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], - "source": "# --- Simulate a biased binary classifier ---\n# Scenario: predicting ICU readmission\n# Protected group (attr=1): elderly patients (age >= 65)\n# Unprotected group (attr=0): younger patients (age < 65)\n\nn_fair = 400\nnp.random.seed(99)\n\n# 40% of patients are elderly\nsensitive = np.random.binomial(1, 0.40, size=n_fair) # 1 = elderly\n\n# True outcomes — elderly have slightly higher readmission rate\ny_true_fair = np.where(\n sensitive == 1,\n np.random.binomial(1, 0.35, size=n_fair), # elderly: 35% readmission\n np.random.binomial(1, 0.25, size=n_fair), # younger: 25% readmission\n).astype(np.float32)\n\n# Biased model: under-predicts readmission for elderly\n# (e.g., trained on historical data that under-tested elderly patients)\ny_prob_fair = np.where(\n sensitive == 1,\n np.random.beta(2, 5, size=n_fair), # lower probs for elderly (biased)\n np.random.beta(3, 4, size=n_fair), # higher probs for younger\n).astype(np.float32)\n\nprint(f\"Patients: {n_fair}\")\nprint(f\"Protected (elderly) group: {sensitive.sum()} ({sensitive.mean():.1%})\")\nprint(f\"True readmission rate — elderly: {y_true_fair[sensitive==1].mean():.1%}\")\nprint(f\"True readmission rate — younger: {y_true_fair[sensitive==0].mean():.1%}\")\nprint(f\"Mean predicted prob — elderly: {y_prob_fair[sensitive==1].mean():.3f}\")\nprint(f\"Mean predicted prob — younger: {y_prob_fair[sensitive==0].mean():.3f}\")" + "source": "# --- Simulate a biased binary classifier ---\n# Scenario: predicting ICU readmission\n# Protected group (attr=1): elderly patients (age >= 65)\n# Unprotected group (attr=0): younger patients (age < 65)\n\nn_fair = 400\nnp.random.seed(99)\n\n# 40% of patients are elderly\nsensitive = np.random.binomial(1, 0.40, size=n_fair) # 1 = elderly\n\n# True outcomes \u2014 elderly have slightly higher readmission rate\ny_true_fair = np.where(\n sensitive == 1,\n np.random.binomial(1, 0.35, size=n_fair), # elderly: 35% readmission\n np.random.binomial(1, 0.25, size=n_fair), # younger: 25% readmission\n).astype(np.float32)\n\n# Biased model: under-predicts readmission for elderly\n# (e.g., trained on historical data that under-tested elderly patients)\ny_prob_fair = np.where(\n sensitive == 1,\n np.random.beta(2, 5, size=n_fair), # lower probs for elderly (biased)\n np.random.beta(3, 4, size=n_fair), # higher probs for younger\n).astype(np.float32)\n\nprint(f\"Patients: {n_fair}\")\nprint(f\"Protected (elderly) group: {sensitive.sum()} ({sensitive.mean():.1%})\")\nprint(f\"True readmission rate \u2014 elderly: {y_true_fair[sensitive==1].mean():.1%}\")\nprint(f\"True readmission rate \u2014 younger: {y_true_fair[sensitive==0].mean():.1%}\")\nprint(f\"Mean predicted prob \u2014 elderly: {y_prob_fair[sensitive==1].mean():.3f}\")\nprint(f\"Mean predicted prob \u2014 younger: {y_prob_fair[sensitive==0].mean():.3f}\")" }, { "cell_type": "code", @@ -131,7 +138,7 @@ "execution_count": null, "metadata": {}, "outputs": [], - "source": "# --- Interpret the results ---\ndi = fairness_results[\"disparate_impact\"]\nspd = fairness_results[\"statistical_parity_difference\"]\n\nprint(\"Interpretation:\")\nprint()\nprint(f\" Disparate Impact = {di:.4f}\")\nif di >= 0.8:\n print(\" ✓ Above 0.8 threshold — model passes the 80% rule\")\nelse:\n print(\" ✗ Below 0.8 threshold — model fails the 80% rule (legally significant in US)\")\nprint()\nprint(f\" Statistical Parity Difference = {spd:.4f}\")\nif abs(spd) < 0.05:\n print(\" ✓ Close to 0 — model predictions are roughly equally distributed across groups\")\nelif spd < 0:\n print(f\" ✗ Negative ({spd:.4f}): protected group is predicted positive {abs(spd):.1%} less often\")\nelse:\n print(f\" Protected group is predicted positive {spd:.1%} more often\")" + "source": "# --- Interpret the results ---\ndi = fairness_results[\"disparate_impact\"]\nspd = fairness_results[\"statistical_parity_difference\"]\n\nprint(\"Interpretation:\")\nprint()\nprint(f\" Disparate Impact = {di:.4f}\")\nif di >= 0.8:\n print(\" \u2713 Above 0.8 threshold \u2014 model passes the 80% rule\")\nelse:\n print(\" \u2717 Below 0.8 threshold \u2014 model fails the 80% rule (legally significant in US)\")\nprint()\nprint(f\" Statistical Parity Difference = {spd:.4f}\")\nif abs(spd) < 0.05:\n print(\" \u2713 Close to 0 \u2014 model predictions are roughly equally distributed across groups\")\nelif spd < 0:\n print(f\" \u2717 Negative ({spd:.4f}): protected group is predicted positive {abs(spd):.1%} less often\")\nelse:\n print(f\" Protected group is predicted positive {spd:.1%} more often\")" }, { "cell_type": "code", @@ -143,12 +150,12 @@ { "cell_type": "markdown", "metadata": {}, - "source": "### Clinical context for fairness metrics\n\nIn the healthcare domain, fairness is particularly important because:\n\n1. **Historical bias in training data:** If a hospital historically provided less aggressive treatment to a subgroup, the training labels may reflect these disparities — and the model will learn to replicate them.\n\n2. **Feature proxies:** Features like ZIP code, insurance type, or language can serve as proxies for race/ethnicity. A model may be technically race-unaware yet still exhibit disparate impact.\n\n3. **Regulatory considerations:** The US 2021 Algorithmic Accountability Act and emerging EU AI Act both require documentation of bias audits for high-risk AI (which includes clinical decision support).\n\n**PyHealth's approach:** Report fairness metrics alongside clinical performance metrics. A model with excellent AUC-ROC but poor disparate impact is not ready for deployment." + "source": "### Clinical context for fairness metrics\n\nIn the healthcare domain, fairness is particularly important because:\n\n1. **Historical bias in training data:** If a hospital historically provided less aggressive treatment to a subgroup, the training labels may reflect these disparities \u2014 and the model will learn to replicate them.\n\n2. **Feature proxies:** Features like ZIP code, insurance type, or language can serve as proxies for race/ethnicity. A model may be technically race-unaware yet still exhibit disparate impact.\n\n3. **Regulatory considerations:** The US 2021 Algorithmic Accountability Act and emerging EU AI Act both require documentation of bias audits for high-risk AI (which includes clinical decision support).\n\n**PyHealth's approach:** Report fairness metrics alongside clinical performance metrics. A model with excellent AUC-ROC but poor disparate impact is not ready for deployment." }, { "cell_type": "markdown", "metadata": {}, - "source": "---\n## Part 5: Integration with Trainer — Getting Raw Predictions\n\nIn practice you'll get predictions from a trained model and then compute any of the above metrics. The Trainer provides two ways:\n\n**Option A — `trainer.evaluate(loader)`:** Returns a dict of metrics using the model's default metric function. Convenient, but limited to the default metrics.\n\n**Option B — `trainer.inference(loader)`:** Returns raw numpy arrays `(y_true, y_prob, loss)`. Use this when you want to compute custom metrics, fairness analysis, or calibration plots.\n\n```python\n# After training (see tutorial_pyhealth_trainer.ipynb)\ny_true, y_prob, loss = trainer.inference(test_loader)\n\n# Now compute any metric combination you want\nbinary_metrics_fn(y_true, y_prob, metrics=[\"roc_auc\", \"pr_auc\", \"ECE\"])\nfairness_metrics_fn(y_true, y_prob, sensitive_attributes=race_labels)\n```\n\nThe decoupling of **inference** from **metric computation** means you can:\n- Cache the raw predictions and recompute metrics without re-running the model\n- Apply post-hoc calibration (Platt scaling, temperature scaling) and re-evaluate\n- Run bootstrap confidence intervals on any metric" + "source": "---\n## Part 5: Integration with Trainer \u2014 Getting Raw Predictions\n\nIn practice you'll get predictions from a trained model and then compute any of the above metrics. The Trainer provides two ways:\n\n**Option A \u2014 `trainer.evaluate(loader)`:** Returns a dict of metrics using the model's default metric function. Convenient, but limited to the default metrics.\n\n**Option B \u2014 `trainer.inference(loader)`:** Returns raw numpy arrays `(y_true, y_prob, loss)`. Use this when you want to compute custom metrics, fairness analysis, or calibration plots.\n\n```python\n# After training (see tutorial_pyhealth_trainer.ipynb)\ny_true, y_prob, loss = trainer.inference(test_loader)\n\n# Now compute any metric combination you want\nbinary_metrics_fn(y_true, y_prob, metrics=[\"roc_auc\", \"pr_auc\", \"ECE\"])\nfairness_metrics_fn(y_true, y_prob, sensitive_attributes=race_labels)\n```\n\nThe decoupling of **inference** from **metric computation** means you can:\n- Cache the raw predictions and recompute metrics without re-running the model\n- Apply post-hoc calibration (Platt scaling, temperature scaling) and re-evaluate\n- Run bootstrap confidence intervals on any metric" }, { "cell_type": "markdown", @@ -169,4 +176,4 @@ }, "nbformat": 4, "nbformat_minor": 5 -} +} \ No newline at end of file diff --git a/examples/tutorials/tutorial_pyhealth_model.ipynb b/examples/tutorials/tutorial_pyhealth_model.ipynb index 71a5affd2..8e4e0ba7c 100644 --- a/examples/tutorials/tutorial_pyhealth_model.ipynb +++ b/examples/tutorials/tutorial_pyhealth_model.ipynb @@ -3,7 +3,14 @@ { "cell_type": "markdown", "metadata": {}, - "source": "# PyHealth Models Tutorial — RNN Deep Dive\n\nThis notebook walks through **`pyhealth.models`** from first principles.\n\nYou will learn:\n- The **`BaseModel`** contract every PyHealth model must satisfy\n- How to create synthetic test data with **`create_sample_dataset()`**\n- The internal architecture of **`RNNLayer`** and **`RNN`** — reading the source code line by line\n- How to run forward and backward passes\n- How **`MultimodalRNN`** handles mixed input types\n\n---" + "source": "# PyHealth Models Tutorial \u2014 RNN Deep Dive\n\nThis notebook walks through **`pyhealth.models`** from first principles.\n\nYou will learn:\n- The **`BaseModel`** contract every PyHealth model must satisfy\n- How to create synthetic test data with **`create_sample_dataset()`**\n- The internal architecture of **`RNNLayer`** and **`RNN`** \u2014 reading the source code line by line\n- How to run forward and backward passes\n- How **`MultimodalRNN`** handles mixed input types\n\n---" + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": "!pip install pyhealth" }, { "cell_type": "code", @@ -15,19 +22,19 @@ { "cell_type": "markdown", "metadata": {}, - "source": "---\n## Part 1: The `BaseModel` Contract\n\nEvery PyHealth model inherits from `BaseModel`, which itself inherits from both `ABC` (abstract base class) and `nn.Module` (PyTorch module).\n\n```python\nclass BaseModel(ABC, nn.Module):\n def __init__(self, dataset: SampleDataset):\n ...\n self.feature_keys = list(dataset.input_schema.keys())\n self.label_keys = list(dataset.output_schema.keys())\n\n def forward(self, **kwargs) -> dict[str, torch.Tensor]:\n # Subclasses implement this\n raise NotImplementedError\n```\n\n### What `BaseModel` provides\n\n| Method | Description |\n|--------|-------------|\n| `device` property | Returns the device the model lives on (CPU / CUDA) |\n| `get_output_size()` | Returns the FC head size (1 for binary, num_classes for multiclass) |\n| `get_loss_function()` | Returns the appropriate loss: BCE for binary/multilabel, CrossEntropy for multiclass |\n| `prepare_y_prob(logits)` | Applies sigmoid (binary/multilabel) or softmax (multiclass) to produce probabilities |\n\n### The `forward()` output contract\n\nEvery `forward(**kwargs)` call returns a dict:\n```python\n{\n \"loss\": torch.Tensor, # scalar — backpropagatable\n \"y_prob\": torch.Tensor, # predicted probabilities\n \"y_true\": torch.Tensor, # ground truth labels\n \"logit\": torch.Tensor, # raw logits before activation\n \"embed\": torch.Tensor, # (optional) patient embeddings, only if embed=True in kwargs\n}\n```\n\nThis uniform interface means any model can plug into the `Trainer` without modification." + "source": "---\n## Part 1: The `BaseModel` Contract\n\nEvery PyHealth model inherits from `BaseModel`, which itself inherits from both `ABC` (abstract base class) and `nn.Module` (PyTorch module).\n\n```python\nclass BaseModel(ABC, nn.Module):\n def __init__(self, dataset: SampleDataset):\n ...\n self.feature_keys = list(dataset.input_schema.keys())\n self.label_keys = list(dataset.output_schema.keys())\n\n def forward(self, **kwargs) -> dict[str, torch.Tensor]:\n # Subclasses implement this\n raise NotImplementedError\n```\n\n### What `BaseModel` provides\n\n| Method | Description |\n|--------|-------------|\n| `device` property | Returns the device the model lives on (CPU / CUDA) |\n| `get_output_size()` | Returns the FC head size (1 for binary, num_classes for multiclass) |\n| `get_loss_function()` | Returns the appropriate loss: BCE for binary/multilabel, CrossEntropy for multiclass |\n| `prepare_y_prob(logits)` | Applies sigmoid (binary/multilabel) or softmax (multiclass) to produce probabilities |\n\n### The `forward()` output contract\n\nEvery `forward(**kwargs)` call returns a dict:\n```python\n{\n \"loss\": torch.Tensor, # scalar \u2014 backpropagatable\n \"y_prob\": torch.Tensor, # predicted probabilities\n \"y_true\": torch.Tensor, # ground truth labels\n \"logit\": torch.Tensor, # raw logits before activation\n \"embed\": torch.Tensor, # (optional) patient embeddings, only if embed=True in kwargs\n}\n```\n\nThis uniform interface means any model can plug into the `Trainer` without modification." }, { "cell_type": "markdown", "metadata": {}, - "source": "---\n## Part 2: Creating Test Data with `create_sample_dataset()`\n\n`create_sample_dataset()` is a convenience helper that:\n1. Accepts a list of raw sample dicts\n2. Fits tokenizers / processors based on the provided schema\n3. Returns an `InMemorySampleDataset` (no disk I/O) ready for model instantiation\n\nThis is exactly how PyHealth's own unit tests create datasets — no MIMIC or real EHR data required." + "source": "---\n## Part 2: Creating Test Data with `create_sample_dataset()`\n\n`create_sample_dataset()` is a convenience helper that:\n1. Accepts a list of raw sample dicts\n2. Fits tokenizers / processors based on the provided schema\n3. Returns an `InMemorySampleDataset` (no disk I/O) ready for model instantiation\n\nThis is exactly how PyHealth's own unit tests create datasets \u2014 no MIMIC or real EHR data required." }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], - "source": "# --- Define raw samples ---\n# Each sample is a dict. Keys must match the schemas below.\nsamples = [\n {\n \"patient_id\": \"patient-0\",\n \"visit_id\": \"visit-0\",\n \"conditions\": [\"E11.9\", \"E11.65\", \"I10\"], # Type 2 DM, hypertension\n \"procedures\": [\"99213\", \"36415\"], # Office visit, blood draw\n \"label\": 1,\n },\n {\n \"patient_id\": \"patient-1\",\n \"visit_id\": \"visit-1\",\n \"conditions\": [\"E11.9\"],\n \"procedures\": [\"99213\"],\n \"label\": 0,\n },\n {\n \"patient_id\": \"patient-2\",\n \"visit_id\": \"visit-2\",\n \"conditions\": [\"E11.22\", \"N18.3\", \"E11.42\"], # DM with CKD and neuropathy\n \"procedures\": [\"99213\", \"86900\", \"81001\"],\n \"label\": 1,\n },\n {\n \"patient_id\": \"patient-3\",\n \"visit_id\": \"visit-3\",\n \"conditions\": [\"E11.65\", \"E11.9\"],\n \"procedures\": [\"36415\"],\n \"label\": 0,\n },\n]\n\n# --- Define schemas ---\n# Processor aliases:\n# 'sequence' → SequenceProcessor (tokenizes a list of codes to integer IDs)\n# 'multi_hot' → MultiHotProcessor (binary vector over vocabulary)\n# 'timeseries' → TimeseriesProcessor (continuous time series)\n# 'tensor' → TensorProcessor (fixed-size dense vector)\n# 'binary' → BinaryLabelProcessor (0 or 1)\ninput_schema = {\"conditions\": \"sequence\", \"procedures\": \"sequence\"}\noutput_schema = {\"label\": \"binary\"}\n\n# --- Create the dataset ---\ndataset = create_sample_dataset(\n samples=samples,\n input_schema=input_schema,\n output_schema=output_schema,\n dataset_name=\"diabetes_demo\",\n task_name=\"mortality\",\n)\n\nprint(\"Dataset type: \", type(dataset).__name__)\nprint(\"Input schema: \", dataset.input_schema)\nprint(\"Output schema: \", dataset.output_schema)\nprint(\"Num samples: \", len(dataset))" + "source": "# --- Define raw samples ---\n# Each sample is a dict. Keys must match the schemas below.\nsamples = [\n {\n \"patient_id\": \"patient-0\",\n \"visit_id\": \"visit-0\",\n \"conditions\": [\"E11.9\", \"E11.65\", \"I10\"], # Type 2 DM, hypertension\n \"procedures\": [\"99213\", \"36415\"], # Office visit, blood draw\n \"label\": 1,\n },\n {\n \"patient_id\": \"patient-1\",\n \"visit_id\": \"visit-1\",\n \"conditions\": [\"E11.9\"],\n \"procedures\": [\"99213\"],\n \"label\": 0,\n },\n {\n \"patient_id\": \"patient-2\",\n \"visit_id\": \"visit-2\",\n \"conditions\": [\"E11.22\", \"N18.3\", \"E11.42\"], # DM with CKD and neuropathy\n \"procedures\": [\"99213\", \"86900\", \"81001\"],\n \"label\": 1,\n },\n {\n \"patient_id\": \"patient-3\",\n \"visit_id\": \"visit-3\",\n \"conditions\": [\"E11.65\", \"E11.9\"],\n \"procedures\": [\"36415\"],\n \"label\": 0,\n },\n]\n\n# --- Define schemas ---\n# Processor aliases:\n# 'sequence' \u2192 SequenceProcessor (tokenizes a list of codes to integer IDs)\n# 'multi_hot' \u2192 MultiHotProcessor (binary vector over vocabulary)\n# 'timeseries' \u2192 TimeseriesProcessor (continuous time series)\n# 'tensor' \u2192 TensorProcessor (fixed-size dense vector)\n# 'binary' \u2192 BinaryLabelProcessor (0 or 1)\ninput_schema = {\"conditions\": \"sequence\", \"procedures\": \"sequence\"}\noutput_schema = {\"label\": \"binary\"}\n\n# --- Create the dataset ---\ndataset = create_sample_dataset(\n samples=samples,\n input_schema=input_schema,\n output_schema=output_schema,\n dataset_name=\"diabetes_demo\",\n task_name=\"mortality\",\n)\n\nprint(\"Dataset type: \", type(dataset).__name__)\nprint(\"Input schema: \", dataset.input_schema)\nprint(\"Output schema: \", dataset.output_schema)\nprint(\"Num samples: \", len(dataset))" }, { "cell_type": "code", @@ -39,7 +46,7 @@ { "cell_type": "markdown", "metadata": {}, - "source": "---\n## Part 3: `RNNLayer` Architecture\n\n`RNNLayer` is a low-level building block that wraps PyTorch's native RNN/LSTM/GRU with:\n- **Dropout** before the recurrent computation\n- **Variable-length sequence support** via pack/pad operations\n- **Bidirectional support** with a down-projection to maintain hidden_size\n\n```python\nclass RNNLayer(nn.Module):\n\n def __init__(\n self,\n input_size: int,\n hidden_size: int,\n rnn_type: str = \"GRU\", # one of \"RNN\", \"LSTM\", \"GRU\"\n num_layers: int = 1,\n dropout: float = 0.5,\n bidirectional: bool = False,\n ):\n ...\n self.dropout_layer = nn.Dropout(dropout)\n rnn_module = getattr(nn, rnn_type) # nn.GRU, nn.LSTM, or nn.RNN\n self.rnn = rnn_module(\n input_size, hidden_size,\n num_layers=num_layers,\n dropout=dropout if num_layers > 1 else 0,\n bidirectional=bidirectional,\n batch_first=True,\n )\n if bidirectional:\n self.down_projection = nn.Linear(hidden_size * 2, hidden_size)\n\n def forward(\n self,\n x: torch.Tensor, # shape: (batch, seq_len, input_size)\n mask: Optional[torch.Tensor] = None, # shape: (batch, seq_len), 1=valid\n ) -> Tuple[torch.Tensor, torch.Tensor]:\n x = self.dropout_layer(x)\n\n # Compute actual sequence lengths from mask (or assume full sequences)\n lengths = torch.sum(mask.int(), dim=-1).cpu() if mask is not None else ...\n lengths = torch.clamp(lengths, min=1) # avoid zero-length sequences\n\n # Pack → RNN → Unpack (cuDNN optimization for variable-length batches)\n x = rnn_utils.pack_padded_sequence(x, lengths, batch_first=True, enforce_sorted=False)\n outputs, _ = self.rnn(x)\n outputs, _ = rnn_utils.pad_packed_sequence(outputs, batch_first=True)\n\n # Extract final hidden state at each sample's actual last position\n last_outputs = outputs[torch.arange(batch_size), (lengths - 1), :]\n\n if self.bidirectional:\n # Concatenate forward/backward final states, then project back to hidden_size\n last_outputs = self.down_projection(last_outputs)\n\n return outputs, last_outputs\n # outputs: (batch, seq_len, hidden_size) — all time steps\n # last_outputs: (batch, hidden_size) — final hidden state\n```\n\n### Key design decisions in `RNNLayer`\n\n1. **`pack_padded_sequence`** — tells cuDNN to skip padding positions, which is both faster and numerically correct. Without this, the RNN would process padding tokens and corrupt the final hidden state.\n\n2. **`lengths = clamp(lengths, min=1)`** — `pack_padded_sequence` raises an error for length-0 sequences (empty visits). Clamping to 1 is a safe fallback.\n\n3. **Bidirectional down-projection** — bidirectional outputs have `2 × hidden_size` channels; the linear layer projects back to `hidden_size` so downstream code sees a consistent dimension regardless of directionality." + "source": "---\n## Part 3: `RNNLayer` Architecture\n\n`RNNLayer` is a low-level building block that wraps PyTorch's native RNN/LSTM/GRU with:\n- **Dropout** before the recurrent computation\n- **Variable-length sequence support** via pack/pad operations\n- **Bidirectional support** with a down-projection to maintain hidden_size\n\n```python\nclass RNNLayer(nn.Module):\n\n def __init__(\n self,\n input_size: int,\n hidden_size: int,\n rnn_type: str = \"GRU\", # one of \"RNN\", \"LSTM\", \"GRU\"\n num_layers: int = 1,\n dropout: float = 0.5,\n bidirectional: bool = False,\n ):\n ...\n self.dropout_layer = nn.Dropout(dropout)\n rnn_module = getattr(nn, rnn_type) # nn.GRU, nn.LSTM, or nn.RNN\n self.rnn = rnn_module(\n input_size, hidden_size,\n num_layers=num_layers,\n dropout=dropout if num_layers > 1 else 0,\n bidirectional=bidirectional,\n batch_first=True,\n )\n if bidirectional:\n self.down_projection = nn.Linear(hidden_size * 2, hidden_size)\n\n def forward(\n self,\n x: torch.Tensor, # shape: (batch, seq_len, input_size)\n mask: Optional[torch.Tensor] = None, # shape: (batch, seq_len), 1=valid\n ) -> Tuple[torch.Tensor, torch.Tensor]:\n x = self.dropout_layer(x)\n\n # Compute actual sequence lengths from mask (or assume full sequences)\n lengths = torch.sum(mask.int(), dim=-1).cpu() if mask is not None else ...\n lengths = torch.clamp(lengths, min=1) # avoid zero-length sequences\n\n # Pack \u2192 RNN \u2192 Unpack (cuDNN optimization for variable-length batches)\n x = rnn_utils.pack_padded_sequence(x, lengths, batch_first=True, enforce_sorted=False)\n outputs, _ = self.rnn(x)\n outputs, _ = rnn_utils.pad_packed_sequence(outputs, batch_first=True)\n\n # Extract final hidden state at each sample's actual last position\n last_outputs = outputs[torch.arange(batch_size), (lengths - 1), :]\n\n if self.bidirectional:\n # Concatenate forward/backward final states, then project back to hidden_size\n last_outputs = self.down_projection(last_outputs)\n\n return outputs, last_outputs\n # outputs: (batch, seq_len, hidden_size) \u2014 all time steps\n # last_outputs: (batch, hidden_size) \u2014 final hidden state\n```\n\n### Key design decisions in `RNNLayer`\n\n1. **`pack_padded_sequence`** \u2014 tells cuDNN to skip padding positions, which is both faster and numerically correct. Without this, the RNN would process padding tokens and corrupt the final hidden state.\n\n2. **`lengths = clamp(lengths, min=1)`** \u2014 `pack_padded_sequence` raises an error for length-0 sequences (empty visits). Clamping to 1 is a safe fallback.\n\n3. **Bidirectional down-projection** \u2014 bidirectional outputs have `2 \u00d7 hidden_size` channels; the linear layer projects back to `hidden_size` so downstream code sees a consistent dimension regardless of directionality." }, { "cell_type": "code", @@ -58,7 +65,7 @@ { "cell_type": "markdown", "metadata": {}, - "source": "---\n## Part 4: `RNN` Model Architecture\n\nThe `RNN` class sits one level above `RNNLayer`. It applies **separate** embedding and RNN layers for each input feature, then concatenates the final hidden states and passes them through a shared fully-connected head.\n\n```python\nclass RNN(BaseModel):\n\n def __init__(\n self,\n dataset: SampleDataset,\n embedding_dim: int = 128,\n hidden_dim: int = 128,\n **kwargs # forwarded to RNNLayer (rnn_type, num_layers, dropout, ...)\n ):\n super().__init__(dataset=dataset)\n\n # One embedding model shared across all features\n self.embedding_model = EmbeddingModel(dataset, embedding_dim)\n\n # One independent RNN layer per feature key\n self.rnn = nn.ModuleDict()\n for feature_key in self.feature_keys:\n self.rnn[feature_key] = RNNLayer(\n input_size=embedding_dim, hidden_size=hidden_dim, **kwargs\n )\n\n # Final FC: concatenation of all hidden states → output\n output_size = self.get_output_size() # 1 for binary\n self.fc = nn.Linear(len(self.feature_keys) * hidden_dim, output_size)\n```\n\n### `RNN.forward()` step by step\n\n```python\n def forward(self, **kwargs):\n patient_emb = []\n\n # 1. Extract value tensors and masks from each feature\n for feature_key in self.feature_keys:\n # Feature is a tuple: (value_tensor, mask_tensor, ...)\n # Schema tells us which tuple index is 'value' and which is 'mask'\n inputs[feature_key] = value\n masks[feature_key] = mask\n\n # 2. Embed all features (tokenized codes → dense vectors)\n embedded = self.embedding_model(inputs, masks=masks)\n # embedded[key] shape:\n # SequenceProcessor → (B, seq_len, D)\n # NestedSequenceProcessor → (B, num_visits, num_codes, D)\n # TimeseriesProcessor → (B, T, D)\n\n # 3. Handle dimensionality:\n for feature_key in self.feature_keys:\n x = embedded[feature_key]\n if x.dim() == 4: # nested: (B, V, C, D) → sum-pool codes → (B, V, D)\n x = x.sum(dim=2)\n elif x.dim() == 2: # static single value: (B, D) → (B, 1, D)\n x = x.unsqueeze(1)\n # Now x is always (B, T, D)\n\n # 4. Run per-feature RNN, take final hidden state\n _, x = self.rnn[feature_key](x, mask)\n patient_emb.append(x) # each x: (B, hidden_dim)\n\n # 5. Concatenate all features' hidden states\n patient_emb = torch.cat(patient_emb, dim=1) # (B, num_features * hidden_dim)\n\n # 6. Project to label space\n logits = self.fc(patient_emb)\n\n # 7. Compute loss, probabilities\n y_true = kwargs[self.label_key]\n loss = self.get_loss_function()(logits, y_true)\n y_prob = self.prepare_y_prob(logits)\n\n return {\"loss\": loss, \"y_prob\": y_prob, \"y_true\": y_true, \"logit\": logits}\n```\n\n**Why separate RNNs per feature?** Different clinical features have different sequence semantics. Diagnosis codes have a different distributional structure than procedure codes. Separate RNNs let each feature develop its own specialized temporal representation before combining." + "source": "---\n## Part 4: `RNN` Model Architecture\n\nThe `RNN` class sits one level above `RNNLayer`. It applies **separate** embedding and RNN layers for each input feature, then concatenates the final hidden states and passes them through a shared fully-connected head.\n\n```python\nclass RNN(BaseModel):\n\n def __init__(\n self,\n dataset: SampleDataset,\n embedding_dim: int = 128,\n hidden_dim: int = 128,\n **kwargs # forwarded to RNNLayer (rnn_type, num_layers, dropout, ...)\n ):\n super().__init__(dataset=dataset)\n\n # One embedding model shared across all features\n self.embedding_model = EmbeddingModel(dataset, embedding_dim)\n\n # One independent RNN layer per feature key\n self.rnn = nn.ModuleDict()\n for feature_key in self.feature_keys:\n self.rnn[feature_key] = RNNLayer(\n input_size=embedding_dim, hidden_size=hidden_dim, **kwargs\n )\n\n # Final FC: concatenation of all hidden states \u2192 output\n output_size = self.get_output_size() # 1 for binary\n self.fc = nn.Linear(len(self.feature_keys) * hidden_dim, output_size)\n```\n\n### `RNN.forward()` step by step\n\n```python\n def forward(self, **kwargs):\n patient_emb = []\n\n # 1. Extract value tensors and masks from each feature\n for feature_key in self.feature_keys:\n # Feature is a tuple: (value_tensor, mask_tensor, ...)\n # Schema tells us which tuple index is 'value' and which is 'mask'\n inputs[feature_key] = value\n masks[feature_key] = mask\n\n # 2. Embed all features (tokenized codes \u2192 dense vectors)\n embedded = self.embedding_model(inputs, masks=masks)\n # embedded[key] shape:\n # SequenceProcessor \u2192 (B, seq_len, D)\n # NestedSequenceProcessor \u2192 (B, num_visits, num_codes, D)\n # TimeseriesProcessor \u2192 (B, T, D)\n\n # 3. Handle dimensionality:\n for feature_key in self.feature_keys:\n x = embedded[feature_key]\n if x.dim() == 4: # nested: (B, V, C, D) \u2192 sum-pool codes \u2192 (B, V, D)\n x = x.sum(dim=2)\n elif x.dim() == 2: # static single value: (B, D) \u2192 (B, 1, D)\n x = x.unsqueeze(1)\n # Now x is always (B, T, D)\n\n # 4. Run per-feature RNN, take final hidden state\n _, x = self.rnn[feature_key](x, mask)\n patient_emb.append(x) # each x: (B, hidden_dim)\n\n # 5. Concatenate all features' hidden states\n patient_emb = torch.cat(patient_emb, dim=1) # (B, num_features * hidden_dim)\n\n # 6. Project to label space\n logits = self.fc(patient_emb)\n\n # 7. Compute loss, probabilities\n y_true = kwargs[self.label_key]\n loss = self.get_loss_function()(logits, y_true)\n y_prob = self.prepare_y_prob(logits)\n\n return {\"loss\": loss, \"y_prob\": y_prob, \"y_true\": y_true, \"logit\": logits}\n```\n\n**Why separate RNNs per feature?** Different clinical features have different sequence semantics. Diagnosis codes have a different distributional structure than procedure codes. Separate RNNs let each feature develop its own specialized temporal representation before combining." }, { "cell_type": "markdown", @@ -91,7 +98,7 @@ "execution_count": null, "metadata": {}, "outputs": [], - "source": "# --- Requesting patient embeddings ---\n# Pass embed=True to get the concatenated hidden state before the FC layer\nwith torch.no_grad():\n output_with_embed = model(**data_batch, embed=True)\n\nprint(\"With embed=True:\")\nprint(f\" embed shape: {output_with_embed['embed'].shape}\")\nprint(f\" Expected: (batch_size=2, num_features={len(model.feature_keys)} × hidden_dim={model.hidden_dim} = {len(model.feature_keys) * model.hidden_dim})\")\nprint()\nprint(\"These embeddings can be used for:\")\nprint(\" - Patient similarity search\")\nprint(\" - Visualization with UMAP / t-SNE\")\nprint(\" - Downstream tasks (transfer learning)\")" + "source": "# --- Requesting patient embeddings ---\n# Pass embed=True to get the concatenated hidden state before the FC layer\nwith torch.no_grad():\n output_with_embed = model(**data_batch, embed=True)\n\nprint(\"With embed=True:\")\nprint(f\" embed shape: {output_with_embed['embed'].shape}\")\nprint(f\" Expected: (batch_size=2, num_features={len(model.feature_keys)} \u00d7 hidden_dim={model.hidden_dim} = {len(model.feature_keys) * model.hidden_dim})\")\nprint()\nprint(\"These embeddings can be used for:\")\nprint(\" - Patient similarity search\")\nprint(\" - Visualization with UMAP / t-SNE\")\nprint(\" - Downstream tasks (transfer learning)\")" }, { "cell_type": "code", @@ -103,7 +110,7 @@ { "cell_type": "markdown", "metadata": {}, - "source": "---\n## Part 6: `MultimodalRNN` — Mixed Input Modalities\n\n`MultimodalRNN` extends `RNN` to handle **heterogeneous inputs**. It automatically classifies each feature into:\n\n- **Sequential** (gets its own `RNNLayer`): `SequenceProcessor`, `NestedSequenceProcessor`, `TimeseriesProcessor`, ...\n- **Non-sequential** (embeddings only, no RNN): `MultiHotProcessor`, `TensorProcessor`\n\nThe architecture:\n```\nconditions (seq) → Embed → RNNLayer → hidden_cond ┐\nvitals (tensor) → Linear → embed_vitals ├→ Concat → FC → logit\nrace (multi_hot) → Linear → embed_race ┘\n```\n\nThe final FC input size is `(num_sequential × hidden_dim) + (num_non_sequential × embedding_dim)`." + "source": "---\n## Part 6: `MultimodalRNN` \u2014 Mixed Input Modalities\n\n`MultimodalRNN` extends `RNN` to handle **heterogeneous inputs**. It automatically classifies each feature into:\n\n- **Sequential** (gets its own `RNNLayer`): `SequenceProcessor`, `NestedSequenceProcessor`, `TimeseriesProcessor`, ...\n- **Non-sequential** (embeddings only, no RNN): `MultiHotProcessor`, `TensorProcessor`\n\nThe architecture:\n```\nconditions (seq) \u2192 Embed \u2192 RNNLayer \u2192 hidden_cond \u2510\nvitals (tensor) \u2192 Linear \u2192 embed_vitals \u251c\u2192 Concat \u2192 FC \u2192 logit\nrace (multi_hot) \u2192 Linear \u2192 embed_race \u2518\n```\n\nThe final FC input size is `(num_sequential \u00d7 hidden_dim) + (num_non_sequential \u00d7 embedding_dim)`." }, { "cell_type": "code", @@ -129,7 +136,7 @@ { "cell_type": "markdown", "metadata": {}, - "source": "---\n## Summary\n\n| Concept | Key API |\n|---------|----------|\n| Create synthetic dataset | `create_sample_dataset(samples, input_schema, output_schema)` |\n| Batch iteration | `get_dataloader(dataset, batch_size=32, shuffle=True)` |\n| Instantiate RNN | `RNN(dataset, embedding_dim=128, hidden_dim=128, rnn_type=\"GRU\")` |\n| Forward pass | `model(**batch)` → `{loss, y_prob, y_true, logit}` |\n| Request embeddings | `model(**batch, embed=True)` → adds `embed` key |\n| Backward pass | `output[\"loss\"].backward()` |\n| Mixed modalities | `MultimodalRNN(dataset, embedding_dim=128, hidden_dim=128)` |\n\n### Choosing hyperparameters\n\n| Hyperparameter | Guidance |\n|----------------|----------|\n| `rnn_type` | GRU is a good default; LSTM has more parameters but can model longer dependencies |\n| `embedding_dim` | 64–256 depending on vocabulary size |\n| `hidden_dim` | Usually equal to `embedding_dim`; increase for more complex patterns |\n| `num_layers` | 1–2; deeper RNNs need dropout > 0 between layers |\n| `dropout` | 0.3–0.5; reduces overfitting on small datasets |\n| `bidirectional` | Only meaningful when the full sequence is available at inference time |" + "source": "---\n## Summary\n\n| Concept | Key API |\n|---------|----------|\n| Create synthetic dataset | `create_sample_dataset(samples, input_schema, output_schema)` |\n| Batch iteration | `get_dataloader(dataset, batch_size=32, shuffle=True)` |\n| Instantiate RNN | `RNN(dataset, embedding_dim=128, hidden_dim=128, rnn_type=\"GRU\")` |\n| Forward pass | `model(**batch)` \u2192 `{loss, y_prob, y_true, logit}` |\n| Request embeddings | `model(**batch, embed=True)` \u2192 adds `embed` key |\n| Backward pass | `output[\"loss\"].backward()` |\n| Mixed modalities | `MultimodalRNN(dataset, embedding_dim=128, hidden_dim=128)` |\n\n### Choosing hyperparameters\n\n| Hyperparameter | Guidance |\n|----------------|----------|\n| `rnn_type` | GRU is a good default; LSTM has more parameters but can model longer dependencies |\n| `embedding_dim` | 64\u2013256 depending on vocabulary size |\n| `hidden_dim` | Usually equal to `embedding_dim`; increase for more complex patterns |\n| `num_layers` | 1\u20132; deeper RNNs need dropout > 0 between layers |\n| `dropout` | 0.3\u20130.5; reduces overfitting on small datasets |\n| `bidirectional` | Only meaningful when the full sequence is available at inference time |" } ], "metadata": { @@ -145,4 +152,4 @@ }, "nbformat": 4, "nbformat_minor": 5 -} +} \ No newline at end of file diff --git a/examples/tutorials/tutorial_pyhealth_tokenizer.ipynb b/examples/tutorials/tutorial_pyhealth_tokenizer.ipynb new file mode 100644 index 000000000..f325c4943 --- /dev/null +++ b/examples/tutorials/tutorial_pyhealth_tokenizer.ipynb @@ -0,0 +1,210 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": "# PyHealth Tokenizer Tutorial\n\nThis notebook covers **`pyhealth.tokenizer`** \u2014 a lightweight utility for converting medical codes (or any string tokens) into integer indices for use with ML models.\n\nYou will learn:\n- How to build a **`Vocabulary`** and use special tokens (``, ``)\n- How to wrap it in a **`Tokenizer`** for batch encoding/decoding\n- How to encode flat lists of codes (**2D**) with padding and truncation\n- How to encode visit-level patient histories (**3D**) for hierarchical models\n- How to build a tokenizer from a real dataset's code vocabulary and feed it to a PyTorch model\n\n> **Why a custom tokenizer?** Clinical codes (ICD, ATC, NDC, custom labels) are categorical and very sparse \u2014 a typical hospital uses only a few thousand of the ~70,000 valid ICD-10 codes. PyHealth's tokenizer is intentionally simple (no subword splitting, no BPE) because each medical code already *is* an atomic token. For free-text clinical notes, use a HuggingFace tokenizer instead.\n\n---" + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": "!pip install pyhealth" + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": "from pyhealth.tokenizer import Vocabulary, Tokenizer" + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": "---\n## Part 1: The `Vocabulary` Class\n\n`Vocabulary` is the underlying token \u2194 index mapping. You will rarely use it directly \u2014 `Tokenizer` wraps it \u2014 but it is useful to understand how special tokens are handled.\n\n```python\nVocabulary(\n tokens: List[str], # the real tokens (ATC codes, ICD codes, drug names\u2026)\n special_tokens: Optional[List[str]] = None, # e.g. ['', '']\n)\n```\n\n### Special token conventions\n\n| Token | Purpose | When required |\n|-------|---------|---------------|\n| `` | Padding token for batch alignment | Required when `padding=True` in batch encoders |\n| `` | Catch-all for unknown tokens | Required if your input may contain tokens outside the vocab; otherwise an unknown token raises `ValueError` |\n\n**Order matters.** Special tokens are inserted *before* the real tokens, so `` will reliably get index `0` and `` will get index `1` when you pass them in that order. This convention is used throughout PyHealth's built-in models (e.g. embedding layers initialize the pad row to zero)." + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": "# Build a vocabulary over the first 8 ATC level-3 codes\natc_codes = ['A01A', 'A02A', 'A02B', 'A02X', 'A03A', 'A03B', 'A03C', 'A03D']\nvocab = Vocabulary(tokens=atc_codes, special_tokens=['', ''])\n\nprint(f'Vocab size: {len(vocab)}')\nprint(f' \u2192 {vocab(\"\")}')\nprint(f' \u2192 {vocab(\"\")}')\nprint(f'A01A \u2192 {vocab(\"A01A\")}')\nprint(f'A03D \u2192 {vocab(\"A03D\")}')" + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": "# Containment check \u2014 useful when sanity-checking external inputs\nprint('\"A03A\" in vocab:', 'A03A' in vocab)\nprint('\"Z99Z\" in vocab:', 'Z99Z' in vocab)\n\n# Calling the vocab with an unknown token falls back to \nprint('vocab(\"Z99Z\") \u2192', vocab('Z99Z'), ' (== index of )')" + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": "### What happens without ``?\n\nIf you build a vocab without `` and then query a token that is not in it, PyHealth raises an exception rather than silently mapping it to a default index. This is the safer default for supervised tasks where every input code should be known." + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": "strict_vocab = Vocabulary(tokens=atc_codes, special_tokens=[''])\ntry:\n strict_vocab('Z99Z')\nexcept ValueError as e:\n print(f'ValueError: {e}')" + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": "---\n## Part 2: The `Tokenizer` Class\n\n`Tokenizer` wraps a `Vocabulary` and adds:\n- single-list encode/decode\n- 2D batch encode/decode (with padding + truncation)\n- 3D batch encode/decode (visit-level, for hierarchical models)\n\n```python\nTokenizer(\n tokens: List[str],\n special_tokens: Optional[List[str]] = None,\n)\n```" + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": "# A more realistic ATC level-3 vocabulary (42 codes, covering ATC 'A' \u2014 alimentary tract)\ntoken_space = [\n 'A01A', 'A02A', 'A02B', 'A02X', 'A03A', 'A03B', 'A03C', 'A03D', 'A03E', 'A03F',\n 'A04A', 'A05A', 'A05B', 'A05C', 'A06A', 'A07A', 'A07B', 'A07C', 'A07D', 'A07E',\n 'A07F', 'A07X', 'A08A', 'A09A', 'A10A', 'A10B', 'A10X', 'A11A', 'A11B', 'A11C',\n 'A11D', 'A11E', 'A11G', 'A11H', 'A11J', 'A12A', 'A12B', 'A12C', 'A13A', 'A14A',\n 'A14B', 'A16A',\n]\n\ntokenizer = Tokenizer(tokens=token_space, special_tokens=['', ''])\n\nprint(f'Vocabulary size: {tokenizer.get_vocabulary_size()}') # 2 specials + 42 codes = 44\nprint(f'Padding index : {tokenizer.get_padding_index()}') # always 0 with this ordering" + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": "---\n## Part 3: Converting Tokens \u2194 Indices\n\nFor a single (1D) list of codes \u2014 e.g. one patient's diagnoses on one visit:" + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": "tokens = ['A03C', 'A03D', 'A03E', 'A03F', 'A04A', 'A05A', 'A05B', 'B035', 'C129']\n# \u2191 \u2191\n# not in vocab \u2014 will map to (= 1)\n\nindices = tokenizer.convert_tokens_to_indices(tokens)\nprint('tokens \u2192 indices:', indices)\n\ntokens_back = tokenizer.convert_indices_to_tokens(indices)\nprint('indices \u2192 tokens :', tokens_back)\nprint()\nprint('Note: \"B035\" and \"C129\" round-trip to \"\" \u2014 the original surface form is lost.')" + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": "---\n## Part 4: 2D Batch Encoding (Padding + Truncation)\n\nIn practice you feed *batches* into a model. `batch_encode_2d` handles padding and truncation in one call.\n\n```python\ntokenizer.batch_encode_2d(\n batch: List[List[str]], # one inner list per sample\n padding: bool = True, # pad shorter lists to the batch maximum\n truncation: bool = True, # truncate longer lists to max_length (keeps the LATEST tokens)\n max_length: int = 512,\n)\n```\n\n**Truncation note:** PyHealth keeps the *most recent* `max_length` tokens (`tokens[-max_length:]`). For longitudinal EHR sequences ordered oldest \u2192 newest, this preserves the most relevant recent history." + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": "batch = [\n ['A03C', 'A03D', 'A03E', 'A03F'], # 4 codes\n ['A04A', 'B035', 'C129'], # 3 codes (with two s)\n]\n\n# Default: pad to the batch maximum (4), no truncation needed\nout1 = tokenizer.batch_encode_2d(batch)\nprint('default (padding=True, truncation=True):')\nprint(' ', out1)\nprint(' shape: 2 rows \u00d7 4 cols \u2014 second row padded with index 0 ()')" + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": "# padding=False: rows keep their natural lengths (jagged \u2014 not directly usable as a tensor)\nout2 = tokenizer.batch_encode_2d(batch, padding=False)\nprint('padding=False:')\nprint(' ', out2)" + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": "# max_length=3 \u2014 forces truncation of the first row (which has 4 codes)\nout3 = tokenizer.batch_encode_2d(batch, max_length=3)\nprint('max_length=3 (drops oldest token of row 0):')\nprint(' ', out3)\nprint()\nprint('Row 0 truncated from [A03C, A03D, A03E, A03F] \u2192 [A03D, A03E, A03F]')\nprint('Then row 1 has length 3 already \u2014 no padding needed, batch max is 3.')" + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": "### Decoding back to tokens\n\n`batch_decode_2d` reverses the encode step. By default it strips `` tokens so you see only the real content. Pass `padding=True` to keep them visible (useful for debugging shape issues)." + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": "indices = [\n [8, 9, 10, 11],\n [12, 1, 1, 0], # \u2190 the trailing 0 is \n]\n\nprint('padding=False (default \u2014 drops ):')\nprint(' ', tokenizer.batch_decode_2d(indices))\nprint()\nprint('padding=True (keep visible):')\nprint(' ', tokenizer.batch_decode_2d(indices, padding=True))" + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": "---\n## Part 5: 3D Batch Encoding for Visit-Level Histories\n\nEHR data is naturally **hierarchical**: a patient has multiple *visits*, each visit has multiple *codes*. Models like RETAIN, GAMENet, and SafeDrug expect input shaped as `[batch, visit, code]`.\n\n`batch_encode_3d` pads and truncates along *both* axes:\n\n```python\ntokenizer.batch_encode_3d(\n batch: List[List[List[str]]],\n padding: Tuple[bool, bool] = (True, True), # (visits, codes)\n truncation: Tuple[bool, bool] = (True, True),\n max_length: Tuple[int, int] = (10, 512), # (max visits, max codes per visit)\n)\n```\n\n| Argument | Axis 0 (visits) | Axis 1 (codes within a visit) |\n|----------|-----------------|-------------------------------|\n| `padding` | Pad batch to longest patient (visit count) | Pad to longest visit (code count) |\n| `truncation` | Keep the most recent `max_length[0]` visits | Keep the most recent `max_length[1]` codes per visit |\n\nThe two axes are controlled independently \u2014 you can pad visits but not codes, etc." + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": "# Two patients with different visit counts and visit-level code counts\npatients = [\n # Patient 0 \u2014 two visits\n [\n ['A03C', 'A03D', 'A03E', 'A03F'], # visit 1 \u2014 4 codes\n ['A08A', 'A09A'], # visit 2 \u2014 2 codes\n ],\n # Patient 1 \u2014 one visit, with two unknown codes\n [\n ['A04A', 'B035', 'C129'],\n ],\n]\n\nout = tokenizer.batch_encode_3d(patients)\nprint('Default (pad both axes):')\nfor i, p in enumerate(out):\n print(f' patient {i}: {p}')" + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": "# pad visits but NOT codes within a visit \u2014 batch becomes jagged on the inner axis\nout = tokenizer.batch_encode_3d(patients, padding=(True, False))\nprint('padding=(visits=True, codes=False):')\nfor i, p in enumerate(out):\n print(f' patient {i}: {p}')" + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": "# Truncate aggressively \u2014 max 2 visits, max 2 codes/visit\nout = tokenizer.batch_encode_3d(patients, max_length=(2, 2))\nprint('max_length=(2 visits, 2 codes per visit):')\nfor i, p in enumerate(out):\n print(f' patient {i}: {p}')\nprint()\nprint('Patient 0 visit 0 truncated from [A03C, A03D, A03E, A03F] \u2192 last 2 = [A03E, A03F]')\nprint('Patient 1 has only 1 visit, so the second visit slot is fully padded.')" + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": "### Decoding 3D batches\n\n`batch_decode_3d` strips fully-padded visits by default. Pass `padding=True` to preserve the full rectangular shape \u2014 useful when you need the indices to align with attention masks or padding masks." + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": "indices_3d = [\n [\n [ 8, 9, 10, 11],\n [24, 25, 0, 0], # \u2190 two trailing pads\n ],\n [\n [12, 1, 1, 0], # \u2190 one trailing pad\n [ 0, 0, 0, 0], # \u2190 fully-padded visit (dropped by default)\n ],\n]\n\nprint('padding=False (default \u2014 drops empty visits):')\nfor i, p in enumerate(tokenizer.batch_decode_3d(indices_3d)):\n print(f' patient {i}: {p}')\n\nprint()\nprint('padding=True (full rectangular shape):')\nfor i, p in enumerate(tokenizer.batch_decode_3d(indices_3d, padding=True)):\n print(f' patient {i}: {p}')" + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": "---\n## Part 6: Practical Pattern \u2014 Build a Tokenizer from a Real Dataset\n\nIn a real training pipeline you don't hard-code the vocabulary \u2014 you build it from the codes that actually appear in your training set. The standard recipe:\n\n1. Iterate over all training samples and collect the unique codes.\n2. Sort them for reproducibility.\n3. Build the tokenizer with `` and `` as special tokens.\n4. Use the tokenizer's `get_vocabulary_size()` to size your embedding layer.\n\nBelow is a self-contained example you can run without downloading any data." + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": "# Simulate a small training set of patient visit histories\nimport random\nrandom.seed(0)\n\n# Pretend these are the ATC codes seen across the training corpus\ncorpus_codes = ['A01A', 'A02A', 'A02B', 'A03A', 'A03B', 'A04A', 'A05A',\n 'A10A', 'A10B', 'A11A', 'A12A', 'B01A', 'B02B', 'C09A']\n\n# 5 patients, each with 1\u20133 visits, each visit with 1\u20135 codes\ntrain_samples = []\nfor _ in range(5):\n n_visits = random.randint(1, 3)\n visits = [random.sample(corpus_codes, k=random.randint(1, 5))\n for _ in range(n_visits)]\n train_samples.append(visits)\n\nfor i, p in enumerate(train_samples):\n print(f'patient {i}: {p}')" + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": "# Step 1: collect the unique codes that actually appear in the training data\nvocab_tokens = sorted({code for patient in train_samples\n for visit in patient\n for code in visit})\nprint(f'Unique codes in training data: {len(vocab_tokens)}')\nprint(vocab_tokens)\n\n# Step 2: build the tokenizer\ntokenizer = Tokenizer(tokens=vocab_tokens, special_tokens=['', ''])\nprint(f'\\nFinal vocab size (incl. specials): {tokenizer.get_vocabulary_size()}')" + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": "# Step 3: encode the full training set in one shot\nencoded = tokenizer.batch_encode_3d(\n train_samples,\n padding=(True, True),\n truncation=(True, True),\n max_length=(5, 10), # max 5 visits, max 10 codes per visit\n)\n\nprint(f'Encoded batch \u2014 outer length: {len(encoded)} patients')\nprint(f' visit count per patient: {[len(p) for p in encoded]}')\nprint(f' codes per visit (patient 0): {[len(v) for v in encoded[0]]}')" + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": "# Step 4 (sketch): use the tokenizer's vocab size as the embedding input dim\n# This is what PyHealth's built-in models do internally:\n#\n# import torch.nn as nn\n# embedding = nn.Embedding(\n# num_embeddings = tokenizer.get_vocabulary_size(),\n# embedding_dim = 128,\n# padding_idx = tokenizer.get_padding_index(), # zero-row for \n# )\n#\n# Passing `padding_idx` ensures gradients don't flow into the pad row \u2014\n# critical for training stability when batches are heavily padded.\n\nprint(f'num_embeddings = {tokenizer.get_vocabulary_size()}')\nprint(f'padding_idx = {tokenizer.get_padding_index()}')" + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": "---\n## Part 7: Where the Tokenizer Fits in PyHealth\n\nMost users never instantiate `Tokenizer` directly. It is used *internally* by:\n\n| Component | Role of the tokenizer |\n|-----------|----------------------|\n| **`pyhealth.processors`** (`SequenceProcessor`, etc.) | Builds a tokenizer per feature key (e.g. one for diagnoses, one for procedures) when the dataset task is registered |\n| **Built-in models** (`RNN`, `Transformer`, `RETAIN`, `GAMENet`, \u2026) | Embeds tokenized inputs and uses `padding_idx` to mask the pad row |\n| **`set_task()`** pipeline | Wires processors + tokenizers into the dataloader so models receive ready-to-embed integer tensors |\n\nYou should reach for `Tokenizer` directly when:\n- You are writing a **custom model** that takes raw code lists instead of pre-processed tensors\n- You are running **inference** on data that was not produced by PyHealth's pipeline (e.g. a CSV of codes)\n- You need to **share a single vocabulary** across multiple datasets or tasks\n\nFor free-text inputs (clinical notes, discharge summaries), don't use this tokenizer \u2014 use a HuggingFace tokenizer inside one of PyHealth's text processors (see the `smart_processor_clinical_text_tutorial.ipynb` example for the canonical pattern)." + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": "---\n## Summary\n\n| Task | API |\n|------|-----|\n| Build a vocabulary | `Vocabulary(tokens, special_tokens=['', ''])` |\n| Build a tokenizer | `Tokenizer(tokens, special_tokens=['', ''])` |\n| Get vocab size | `tokenizer.get_vocabulary_size()` |\n| Get pad index | `tokenizer.get_padding_index()` |\n| Encode one list | `tokenizer.convert_tokens_to_indices(tokens)` |\n| Decode one list | `tokenizer.convert_indices_to_tokens(indices)` |\n| Encode 2D batch | `tokenizer.batch_encode_2d(batch, padding=True, truncation=True, max_length=512)` |\n| Decode 2D batch | `tokenizer.batch_decode_2d(batch, padding=False)` |\n| Encode 3D batch | `tokenizer.batch_encode_3d(batch, padding=(True, True), truncation=(True, True), max_length=(10, 512))` |\n| Decode 3D batch | `tokenizer.batch_decode_3d(batch, padding=False)` |\n\n### Quick design checklist\n\n- Always include `` if you will batch with `padding=True`.\n- Include `` if you cannot guarantee a closed vocabulary at inference time.\n- Order specials as `['', '']` so the pad index is `0` (matches PyHealth's model defaults).\n- Build the vocab from the **training set only** \u2014 unseen codes at validation/test time should map to ``.\n- For hierarchical EHR models, use `batch_encode_3d` with explicit `max_length` to cap GPU memory." + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python", + "version": "3.9.0" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} \ No newline at end of file diff --git a/examples/tutorials/tutorial_pyhealth_trainer.ipynb b/examples/tutorials/tutorial_pyhealth_trainer.ipynb index c5ee70f56..f32b3cf9d 100644 --- a/examples/tutorials/tutorial_pyhealth_trainer.ipynb +++ b/examples/tutorials/tutorial_pyhealth_trainer.ipynb @@ -3,7 +3,14 @@ { "cell_type": "markdown", "metadata": {}, - "source": "# PyHealth Trainer Tutorial — End-to-End Training with MIMIC-III\n\nThis notebook covers **`pyhealth.trainer`** — the training loop that ties datasets, models, and metrics together.\n\nYou will learn:\n- How to load a public **synthetic MIMIC-III** dataset (no credentials required)\n- How to apply a **mortality prediction task** to generate model-ready samples\n- How to split, batch, and feed data to an **RNN model**\n- How to use **`Trainer`** for training with validation, early stopping, and checkpointing\n- How to **evaluate** a trained model on a held-out test set\n\n> **Dataset Note:** The dataset used here is a fully synthetic MIMIC-III replica hosted by Google Cloud Storage. No PhysioNet account or data use agreement is needed.\n\n---" + "source": "# PyHealth Trainer Tutorial \u2014 End-to-End Training with MIMIC-III\n\nThis notebook covers **`pyhealth.trainer`** \u2014 the training loop that ties datasets, models, and metrics together.\n\nYou will learn:\n- How to load a public **synthetic MIMIC-III** dataset (no credentials required)\n- How to apply a **mortality prediction task** to generate model-ready samples\n- How to split, batch, and feed data to an **RNN model**\n- How to use **`Trainer`** for training with validation, early stopping, and checkpointing\n- How to **evaluate** a trained model on a held-out test set\n\n> **Dataset Note:** The dataset used here is a fully synthetic MIMIC-III replica hosted by Google Cloud Storage. No PhysioNet account or data use agreement is needed.\n\n---" + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": "!pip install pyhealth" }, { "cell_type": "code", @@ -15,7 +22,7 @@ { "cell_type": "markdown", "metadata": {}, - "source": "---\n## Step 1: Load the Synthetic MIMIC-III Dataset\n\n`MIMIC3Dataset` loads structured EHR tables from a root directory (local path or URL). The Google Cloud Storage path below hosts a synthetic copy — the schema is identical to real MIMIC-III but no real patient data is present.\n\nDefault tables always loaded: `[\"patients\", \"admissions\", \"icustays\"]`\nAdditional tables you can specify:\n- `\"diagnoses_icd\"` — ICD-9 diagnosis codes per admission\n- `\"procedures_icd\"` — ICD-9 procedure codes per admission\n- `\"prescriptions\"` — Medication orders (NDC codes)\n- `\"labevents\"` — Lab measurements\n- `\"noteevents\"` — Clinical notes (discharge summaries, radiology reports, etc.)" + "source": "---\n## Step 1: Load the Synthetic MIMIC-III Dataset\n\n`MIMIC3Dataset` loads structured EHR tables from a root directory (local path or URL). The Google Cloud Storage path below hosts a synthetic copy \u2014 the schema is identical to real MIMIC-III but no real patient data is present.\n\nDefault tables always loaded: `[\"patients\", \"admissions\", \"icustays\"]`\nAdditional tables you can specify:\n- `\"diagnoses_icd\"` \u2014 ICD-9 diagnosis codes per admission\n- `\"procedures_icd\"` \u2014 ICD-9 procedure codes per admission\n- `\"prescriptions\"` \u2014 Medication orders (NDC codes)\n- `\"labevents\"` \u2014 Lab measurements\n- `\"noteevents\"` \u2014 Clinical notes (discharge summaries, radiology reports, etc.)" }, { "cell_type": "code", @@ -46,7 +53,7 @@ { "cell_type": "markdown", "metadata": {}, - "source": "---\n## Step 3: Split the Dataset\n\n`split_by_patient` partitions samples so that **no patient appears in more than one split** — this is the correct way to split clinical data. Splitting by sample (the naive approach) would allow data leakage: a model could see one visit from patient X in training and another visit from the same patient in test.\n\nReturns three `SampleDataset` objects sharing the same fitted processors." + "source": "---\n## Step 3: Split the Dataset\n\n`split_by_patient` partitions samples so that **no patient appears in more than one split** \u2014 this is the correct way to split clinical data. Splitting by sample (the naive approach) would allow data leakage: a model could see one visit from patient X in training and another visit from the same patient in test.\n\nReturns three `SampleDataset` objects sharing the same fitted processors." }, { "cell_type": "code", @@ -154,7 +161,7 @@ { "cell_type": "markdown", "id": "b8313bc0", - "source": "---\n## API Reference: Available Metric Strings\n\nThe `metrics` argument to `Trainer.__init__` and the `monitor` argument to `trainer.train()` are plain strings drawn from a fixed list. The exact list depends on **`model.mode`**, which is set automatically from the task's output schema:\n\n```python\nprint(model.mode) # → \"binary\" | \"multiclass\" | \"multilabel\" | \"regression\"\n```\n\n`Trainer` uses `model.mode` to select the right metrics function, then passes your `metrics` list to it. Any string you pass to `monitor` must appear in that same list — otherwise evaluation will raise a `KeyError`.\n\nTo compute a non-default set of metrics and track a specific one:\n```python\ntrainer = Trainer(\n model=model,\n metrics=[\"roc_auc\", \"pr_auc\", \"balanced_accuracy\", \"ECE\"], # computed every eval epoch\n)\ntrainer.train(..., monitor=\"pr_auc\", monitor_criterion=\"max\")\n```\n\n---\n\n### Binary classification — `mode = \"binary\"`\n**Source:** `pyhealth.metrics.binary_metrics_fn` \n**Defaults when `metrics=None`:** `[\"pr_auc\", \"roc_auc\", \"f1\"]`\n\n| Metric string | Description | `monitor_criterion` |\n|---|---|---|\n| `\"pr_auc\"` | Area under the Precision-Recall curve | `\"max\"` |\n| `\"roc_auc\"` | Area under the ROC curve | `\"max\"` |\n| `\"f1\"` | F1 score at `threshold` (default 0.5) | `\"max\"` |\n| `\"accuracy\"` | Fraction of correct predictions | `\"max\"` |\n| `\"balanced_accuracy\"` | Accuracy adjusted for class imbalance | `\"max\"` |\n| `\"precision\"` | Precision at `threshold` | `\"max\"` |\n| `\"recall\"` | Recall at `threshold` | `\"max\"` |\n| `\"cohen_kappa\"` | Cohen's kappa (agreement beyond chance) | `\"max\"` |\n| `\"jaccard\"` | Jaccard similarity coefficient | `\"max\"` |\n| `\"ECE\"` | Expected Calibration Error (20 equal-width bins) | `\"min\"` |\n| `\"ECE_adapt\"` | Adaptive ECE (20 equal-size bins) | `\"min\"` |\n\n---\n\n### Multiclass classification — `mode = \"multiclass\"`\n**Source:** `pyhealth.metrics.multiclass_metrics_fn` \n**Defaults when `metrics=None`:** `[\"accuracy\", \"f1_macro\", \"f1_micro\"]`\n\n| Metric string | Description | `monitor_criterion` |\n|---|---|---|\n| `\"accuracy\"` | Overall accuracy | `\"max\"` |\n| `\"balanced_accuracy\"` | Accuracy adjusted for class imbalance | `\"max\"` |\n| `\"f1_macro\"` | F1, macro-averaged across classes | `\"max\"` |\n| `\"f1_micro\"` | F1, micro-averaged across classes | `\"max\"` |\n| `\"f1_weighted\"` | F1, weighted by class support | `\"max\"` |\n| `\"roc_auc_macro_ovo\"` | ROC-AUC, macro, one-vs-one | `\"max\"` |\n| `\"roc_auc_macro_ovr\"` | ROC-AUC, macro, one-vs-rest | `\"max\"` |\n| `\"roc_auc_weighted_ovo\"` | ROC-AUC, weighted, one-vs-one | `\"max\"` |\n| `\"roc_auc_weighted_ovr\"` | ROC-AUC, weighted, one-vs-rest | `\"max\"` |\n| `\"jaccard_micro\"` | Jaccard, micro-averaged | `\"max\"` |\n| `\"jaccard_macro\"` | Jaccard, macro-averaged | `\"max\"` |\n| `\"jaccard_weighted\"` | Jaccard, weighted | `\"max\"` |\n| `\"cohen_kappa\"` | Cohen's kappa | `\"max\"` |\n| `\"brier_top1\"` | Brier score for the top predicted class | `\"min\"` |\n| `\"ECE\"` | Expected Calibration Error (20 equal-width bins) | `\"min\"` |\n| `\"ECE_adapt\"` | Adaptive ECE (20 equal-size bins) | `\"min\"` |\n| `\"cwECEt\"` | Classwise ECE with threshold = min(0.01, 1/K) | `\"min\"` |\n| `\"cwECEt_adapt\"` | Classwise adaptive ECE | `\"min\"` |\n| `\"hits@n\"` | HITS@1 / HITS@5 / HITS@10 (produces 3 dict keys) | `\"max\"` |\n| `\"mean_rank\"` | Mean rank + mean reciprocal rank | `\"min\"` |\n\n---\n\n### Multilabel classification — `mode = \"multilabel\"`\n**Source:** `pyhealth.metrics.multilabel_metrics_fn` \n**Defaults when `metrics=None`:** `[\"pr_auc_samples\"]` \n**Note:** threshold defaults to `0.3` (not `0.5`) — lower thresholds are common in drug recommendation tasks.\n\n| Metric string | Description | `monitor_criterion` |\n|---|---|---|\n| `\"pr_auc_samples\"` | PR-AUC, averaged across samples | `\"max\"` |\n| `\"pr_auc_micro\"` | PR-AUC, micro-averaged | `\"max\"` |\n| `\"pr_auc_macro\"` | PR-AUC, macro-averaged | `\"max\"` |\n| `\"pr_auc_weighted\"` | PR-AUC, weighted | `\"max\"` |\n| `\"roc_auc_samples\"` | ROC-AUC, samples-averaged | `\"max\"` |\n| `\"roc_auc_micro\"` | ROC-AUC, micro-averaged | `\"max\"` |\n| `\"roc_auc_macro\"` | ROC-AUC, macro-averaged | `\"max\"` |\n| `\"roc_auc_weighted\"` | ROC-AUC, weighted | `\"max\"` |\n| `\"f1_samples\"` | F1, samples-averaged | `\"max\"` |\n| `\"f1_micro\"` | F1, micro-averaged | `\"max\"` |\n| `\"f1_macro\"` | F1, macro-averaged | `\"max\"` |\n| `\"f1_weighted\"` | F1, weighted | `\"max\"` |\n| `\"precision_micro\"` / `\"_macro\"` / `\"_weighted\"` / `\"_samples\"` | Precision variants | `\"max\"` |\n| `\"recall_micro\"` / `\"_macro\"` / `\"_weighted\"` / `\"_samples\"` | Recall variants | `\"max\"` |\n| `\"jaccard_micro\"` / `\"_macro\"` / `\"_weighted\"` / `\"_samples\"` | Jaccard variants | `\"max\"` |\n| `\"accuracy\"` | Element-wise accuracy | `\"max\"` |\n| `\"hamming_loss\"` | Hamming loss | `\"min\"` |\n| `\"ddi\"` | Drug-drug interaction rate (drug recommendation only) | `\"min\"` |\n| `\"cwECE\"` | Classwise ECE (20 equal-width bins) | `\"min\"` |\n| `\"cwECE_adapt\"` | Classwise adaptive ECE | `\"min\"` |\n\n---\n\n### Regression — `mode = \"regression\"`\n**Source:** `pyhealth.metrics.regression_metrics_fn` \n**Defaults when `metrics=None`:** `[\"kl_divergence\", \"mse\", \"mae\"]`\n\n| Metric string | Description | `monitor_criterion` |\n|---|---|---|\n| `\"mae\"` | Mean Absolute Error | `\"min\"` |\n| `\"mse\"` | Mean Squared Error | `\"min\"` |\n| `\"kl_divergence\"` | KL divergence between true and reconstructed distributions | `\"min\"` |", + "source": "---\n## API Reference: Available Metric Strings\n\nThe `metrics` argument to `Trainer.__init__` and the `monitor` argument to `trainer.train()` are plain strings drawn from a fixed list. The exact list depends on **`model.mode`**, which is set automatically from the task's output schema:\n\n```python\nprint(model.mode) # \u2192 \"binary\" | \"multiclass\" | \"multilabel\" | \"regression\"\n```\n\n`Trainer` uses `model.mode` to select the right metrics function, then passes your `metrics` list to it. Any string you pass to `monitor` must appear in that same list \u2014 otherwise evaluation will raise a `KeyError`.\n\nTo compute a non-default set of metrics and track a specific one:\n```python\ntrainer = Trainer(\n model=model,\n metrics=[\"roc_auc\", \"pr_auc\", \"balanced_accuracy\", \"ECE\"], # computed every eval epoch\n)\ntrainer.train(..., monitor=\"pr_auc\", monitor_criterion=\"max\")\n```\n\n---\n\n### Binary classification \u2014 `mode = \"binary\"`\n**Source:** `pyhealth.metrics.binary_metrics_fn` \n**Defaults when `metrics=None`:** `[\"pr_auc\", \"roc_auc\", \"f1\"]`\n\n| Metric string | Description | `monitor_criterion` |\n|---|---|---|\n| `\"pr_auc\"` | Area under the Precision-Recall curve | `\"max\"` |\n| `\"roc_auc\"` | Area under the ROC curve | `\"max\"` |\n| `\"f1\"` | F1 score at `threshold` (default 0.5) | `\"max\"` |\n| `\"accuracy\"` | Fraction of correct predictions | `\"max\"` |\n| `\"balanced_accuracy\"` | Accuracy adjusted for class imbalance | `\"max\"` |\n| `\"precision\"` | Precision at `threshold` | `\"max\"` |\n| `\"recall\"` | Recall at `threshold` | `\"max\"` |\n| `\"cohen_kappa\"` | Cohen's kappa (agreement beyond chance) | `\"max\"` |\n| `\"jaccard\"` | Jaccard similarity coefficient | `\"max\"` |\n| `\"ECE\"` | Expected Calibration Error (20 equal-width bins) | `\"min\"` |\n| `\"ECE_adapt\"` | Adaptive ECE (20 equal-size bins) | `\"min\"` |\n\n---\n\n### Multiclass classification \u2014 `mode = \"multiclass\"`\n**Source:** `pyhealth.metrics.multiclass_metrics_fn` \n**Defaults when `metrics=None`:** `[\"accuracy\", \"f1_macro\", \"f1_micro\"]`\n\n| Metric string | Description | `monitor_criterion` |\n|---|---|---|\n| `\"accuracy\"` | Overall accuracy | `\"max\"` |\n| `\"balanced_accuracy\"` | Accuracy adjusted for class imbalance | `\"max\"` |\n| `\"f1_macro\"` | F1, macro-averaged across classes | `\"max\"` |\n| `\"f1_micro\"` | F1, micro-averaged across classes | `\"max\"` |\n| `\"f1_weighted\"` | F1, weighted by class support | `\"max\"` |\n| `\"roc_auc_macro_ovo\"` | ROC-AUC, macro, one-vs-one | `\"max\"` |\n| `\"roc_auc_macro_ovr\"` | ROC-AUC, macro, one-vs-rest | `\"max\"` |\n| `\"roc_auc_weighted_ovo\"` | ROC-AUC, weighted, one-vs-one | `\"max\"` |\n| `\"roc_auc_weighted_ovr\"` | ROC-AUC, weighted, one-vs-rest | `\"max\"` |\n| `\"jaccard_micro\"` | Jaccard, micro-averaged | `\"max\"` |\n| `\"jaccard_macro\"` | Jaccard, macro-averaged | `\"max\"` |\n| `\"jaccard_weighted\"` | Jaccard, weighted | `\"max\"` |\n| `\"cohen_kappa\"` | Cohen's kappa | `\"max\"` |\n| `\"brier_top1\"` | Brier score for the top predicted class | `\"min\"` |\n| `\"ECE\"` | Expected Calibration Error (20 equal-width bins) | `\"min\"` |\n| `\"ECE_adapt\"` | Adaptive ECE (20 equal-size bins) | `\"min\"` |\n| `\"cwECEt\"` | Classwise ECE with threshold = min(0.01, 1/K) | `\"min\"` |\n| `\"cwECEt_adapt\"` | Classwise adaptive ECE | `\"min\"` |\n| `\"hits@n\"` | HITS@1 / HITS@5 / HITS@10 (produces 3 dict keys) | `\"max\"` |\n| `\"mean_rank\"` | Mean rank + mean reciprocal rank | `\"min\"` |\n\n---\n\n### Multilabel classification \u2014 `mode = \"multilabel\"`\n**Source:** `pyhealth.metrics.multilabel_metrics_fn` \n**Defaults when `metrics=None`:** `[\"pr_auc_samples\"]` \n**Note:** threshold defaults to `0.3` (not `0.5`) \u2014 lower thresholds are common in drug recommendation tasks.\n\n| Metric string | Description | `monitor_criterion` |\n|---|---|---|\n| `\"pr_auc_samples\"` | PR-AUC, averaged across samples | `\"max\"` |\n| `\"pr_auc_micro\"` | PR-AUC, micro-averaged | `\"max\"` |\n| `\"pr_auc_macro\"` | PR-AUC, macro-averaged | `\"max\"` |\n| `\"pr_auc_weighted\"` | PR-AUC, weighted | `\"max\"` |\n| `\"roc_auc_samples\"` | ROC-AUC, samples-averaged | `\"max\"` |\n| `\"roc_auc_micro\"` | ROC-AUC, micro-averaged | `\"max\"` |\n| `\"roc_auc_macro\"` | ROC-AUC, macro-averaged | `\"max\"` |\n| `\"roc_auc_weighted\"` | ROC-AUC, weighted | `\"max\"` |\n| `\"f1_samples\"` | F1, samples-averaged | `\"max\"` |\n| `\"f1_micro\"` | F1, micro-averaged | `\"max\"` |\n| `\"f1_macro\"` | F1, macro-averaged | `\"max\"` |\n| `\"f1_weighted\"` | F1, weighted | `\"max\"` |\n| `\"precision_micro\"` / `\"_macro\"` / `\"_weighted\"` / `\"_samples\"` | Precision variants | `\"max\"` |\n| `\"recall_micro\"` / `\"_macro\"` / `\"_weighted\"` / `\"_samples\"` | Recall variants | `\"max\"` |\n| `\"jaccard_micro\"` / `\"_macro\"` / `\"_weighted\"` / `\"_samples\"` | Jaccard variants | `\"max\"` |\n| `\"accuracy\"` | Element-wise accuracy | `\"max\"` |\n| `\"hamming_loss\"` | Hamming loss | `\"min\"` |\n| `\"ddi\"` | Drug-drug interaction rate (drug recommendation only) | `\"min\"` |\n| `\"cwECE\"` | Classwise ECE (20 equal-width bins) | `\"min\"` |\n| `\"cwECE_adapt\"` | Classwise adaptive ECE | `\"min\"` |\n\n---\n\n### Regression \u2014 `mode = \"regression\"`\n**Source:** `pyhealth.metrics.regression_metrics_fn` \n**Defaults when `metrics=None`:** `[\"kl_divergence\", \"mse\", \"mae\"]`\n\n| Metric string | Description | `monitor_criterion` |\n|---|---|---|\n| `\"mae\"` | Mean Absolute Error | `\"min\"` |\n| `\"mse\"` | Mean Squared Error | `\"min\"` |\n| `\"kl_divergence\"` | KL divergence between true and reconstructed distributions | `\"min\"` |", "metadata": {} } ],