eICU MEDS Extraction ETL
This repository contains the code for downloading the eICU dataset from PhysioNet and transforming it into the Medical Event Data Standard (MEDS) format.
pip install eICU-MEDS
export DATASET_DOWNLOAD_USERNAME=$PHYSIONET_USERNAME
export DATASET_DOWNLOAD_PASSWORD=$PHYSIONET_PASSWORD
MEDS_extract-eICU root_output_dir=data/eicu_meds
When you run this, the program will:
- Download the raw eICU-CRD tables this ETL reads (see
Which eICU tables are extracted) for the currently supported version into
$ROOT_OUTPUT_DIR/raw_input(via MEDS-Extract's download layer; files that already exist and verify against PhysioNet'sSHA256SUMS.txtare skipped, so an interrupted run resumes rather than restarting). - Construct the MEDS cohort directly from those raw files — every transformation, join,
and pseudotime derivation is declared in
src/eICU_MEDS/configs/event_configs.yaml— and write it to$ROOT_OUTPUT_DIR/MEDS_output.
The public demo needs no credentials:
MEDS_extract-eICU root_output_dir=data/eicu_demo do_demo=True
You can also point the raw and output directories somewhere else directly.
root_output_dir is still required, since the intermediate pre_MEDS tables and the
logs are written under it:
MEDS_extract-eICU root_output_dir=$ROOT_OUTPUT_DIR \
raw_input_dir=$RAW_INPUT_DIR MEDS_output_dir=$MEDS_OUTPUT_DIR
A note on time in eICU
eICU contains no absolute timestamps. Every table records an integer offset in minutes relative to unit admission, and health-system stays are ordered only at year granularity. This pipeline therefore:
- uses the health system stay (
patienthealthsystemstayid) as the MEDSsubject_id, since events are well ordered only within a stay; and - anchors each stay at a constant, arbitrary pseudo-date (December 31 of the recorded discharge year, at the recorded discharge clock time) and derives every event time by offsetting from it.
Only relative time differences within a subject are meaningful. Absolute dates in the output are not real and must not be interpreted as such: because every stay ends on December 31, the date of an event reveals how long until hospital discharge. See docs/data_leakage.md for this and every other way the output can leak information, table by table.
Death
MEDS_DEATH is emitted at hospital discharge when hospitalDischargeStatus == "Expired", and from
no other field. The
documentation
describes Expired as the patient's condition on leaving the hospital, and on the full release it
agrees with the independently populated hospitalDischargeLocation == "Death" on every one of the
200,859 rows (18,004 deaths).
Hospital rather than unit status is the key because it is the more complete of the two: 7,315 rows
record a unit discharge Alive followed by a hospital death, which unit status would miss.
The converse is deliberately not used. 222 rows (0.1%) have unitDischargeStatus == "Expired"
while hospital status is Alive or blank, and these emit no MEDS_DEATH. They contradict
themselves: in 142 of them the hospital stay continues past the unit discharge at which the
patient supposedly died, some to a discharge home. Rows with a blank hospital status (1,751) are
likewise not treated as deaths. See
#11.
Vital signs: only measurements that happened
vitalPeriodic and vitalAperiodic are wide tables — one row per timestamp, one column per
vital sign — and most cells are empty. A row that recorded a heart rate still carries columns
for intracranial pressure, end-tidal CO2 and the pulmonary-artery pressures, which need
invasive lines that most patients never have.
Each vital's code is therefore guarded so that a missing cell emits no event, rather than an event asserting the measurement was taken with no value attached. Without the guard the full cohort carries 2.60 billion vitals rows of which 69.8% are empty; with it, 785 million, all of them real. Per-vital emptiness in the raw data ranges from 0.5% (heart rate) to 98.2% (intracranial pressure).
The guard is written if $x == $x, which is true for any present value — including 0, inf
and NaN — and null for a missing one, which nulls the code and drops the row. It reads oddly
because dftly has no null test; if $x will not type-check against a float column and a bare
null parses as the string "null". Tracked in
dftly#113; this becomes if is_present($x)
once that lands.
NaN and inf are deliberately preserved rather than dropped — they are recorded values, and
changing that is a data-modelling decision rather than a bug fix.
Numeric-value guards
numeric_value is strict-cast downstream, so a String source column containing a single
non-numeric row aborts the stage. Which columns are String is not inferable from the demo — it
depends on what junk happens to appear — so the guarded set comes from the official eICU DDL
(MIT-LCP/eicu-code, postgres_create_tables.sql): age, medication.dosage,
infusiondrug.{infusionrate, patientweight}, nurseCharting.nursingChartValue,
respiratoryCharting.respChartValue, nurseAssessment.cellAttributeValue,
nurseCare.cellAttributeValue and physicalExam.physicalExamText.
Numeric-typed columns are passed through bare, since the schema forbids junk in them.
Where the non-numeric remainder is worth keeping (charted values, below), the same pattern also
appears negated as a regex match, $x if not (/<guard>/ in $x), to fill text_value, so each
event carries exactly one of the two values.
The guard regex is exactly Rust's f64::from_str grammar, so it is value-for-value identical to
polars' non-strict cast. A narrower hand-rolled pattern silently drops real values such as
1e5, 25. and +5; tests/test_numeric_guard.py pins the equivalence by differential
fuzzing.
Charted observations
Several tables record each observation as one varchar cell under picklist labels or a label path. Each row becomes one event whose code is the table's prefix followed by those labels:
| Table | Code | Time | Full-release rows | Blank (no event) | Entry = chart offset | Entry lag, 90th percentile |
|---|---|---|---|---|---|---|
nurseCharting |
NURSE_CHARTING//<category>//<label>//<name> |
nursingChartEntryOffset |
151,604,232 | 284,600 | 73% | 57 min |
respiratoryCharting |
RESPIRATORY_CHARTING//<category>//<label> |
respChartEntryOffset |
20,168,176 | 3 | 75% | 47 min |
nurseAssessment |
NURSE_ASSESSMENT//<cellAttributePath> |
nurseAssessEntryOffset |
15,602,498 | 0 | 5% | 195 min |
nurseCare |
NURSE_CARE//<cellAttributePath> |
nurseCareEntryOffset |
8,311,132 | 0 | 5% | 206 min |
- A value the numeric guard accepts goes to
numeric_value. Anything else, such as GCS descriptors (4-->(E4) spontaneous),Oral,WDLorNasal cannula, goes totext_value. A value written as a percentage (35%) is text: stripping the%would need a second guard pattern. - A blank cell emits no event.
- The time is the entry offset, not the charted offset, so a value is not visible before it was recorded. The last two columns show how far apart the two are.
- The category is part of the code because the same label can sit under more than one category:
PAunder bothInvasiveandVital SignsinnurseCharting(96 codes from 83 label/name pairs on the full release), and 198 codes from 194 labels inrespiratoryCharting. - In the path-coded tables the path ends in the attribute (
…|Neurologic|Pupils|Right) and determines the label, so the path alone is the code. They cover few stays:nurseAssessmenthas rows for 13,001 andnurseCarefor 13,052 of the 200,859 unit stays on the full release. - Vitals charted here overlap with
vitalPeriodic/vitalAperiodic. They keep their own source-prefixed codes, and nothing is deduplicated across tables. - The two charted tables overlap in one measurement: on the full release, 79% of
respiratoryCharting'sRR (patient)values repeatnurseCharting'sRespiratory Ratefor the same stay at the same minute. Ventilator settings and measurements (PEEP, tidal volume, pressure support, plateau pressure, compliance) appear only inrespiratoryCharting.
Intake and output
intakeOutput is the nursing intake/output flowsheet. Each row becomes one
INTAKE_OUTPUT//<cellPath> event, for example
INTAKE_OUTPUT//flowsheet|Flowsheet Cell Labels|I&O|Output (ml)|Urine, valued by the row's own
cellValueNumeric and timed at intakeOutputEntryOffset, as for the charted tables. The path ends
in the row's label, so the label adds nothing to the code.
intakeTotal,outputTotal,dialysisTotalandnetTotalare not emitted. The documentation describes them as cumulative up to the row's offset and repeated across rows entered at the same time, so emitting them would count the same fluid many times.cellValueTextis not emitted. It is the same number written as text.- Rows are not deduplicated. On the full release 9,619 rows repeat another row in everything but their ID, and the table gives no way to tell a repeated entry from two equal ones.
- The documentation says
cellValueNumericis always positive. 1,476 full-release rows are negative, and they are emitted as recorded.
Physical exam
physicalExam holds the structured physical exam entered in eCareManager. Each row becomes one
PHYSICAL_EXAM//<physicalExamPath> event, for example
PHYSICAL_EXAM//notes/Progress Notes/Physical Exam/Physical Exam/Neurologic/GCS/Motor Score/6,
timed at physicalExamOffset, the table's only offset, which the documentation describes as the
time the item was entered.
- The path ends in the picklist choice (
physicalExamValue), so the choice is already in the code. physicalExamTextis split like the charted values. For 63 vital-sign, weight and I&O items (HR Current,Weight (kg)/Admission, …) it is the measurement and goes tonumeric_value; for the other items it mostly repeats the choice and goes totext_value.- A blank text does not drop the event, because the path is the finding. On the full release 41,327 rows have a blank text, all in items that are not measurements, and their events carry no value.
- The vital signs here are the exam's summaries (current, lowest and highest over 24 hours). Like
the charted vitals, they keep their own codes and are not deduplicated against
vitalPeriodic.
Code metadata: descriptions
metadata/codes.parquet carries code, description, parent_codes and code_template. eICU
ships no code dictionary (nothing like MIMIC-IV's d_labitems): its tables record the names
themselves (labName, drugName, treatmentString, diagnosisString), so the codes are
human-readable on their own and releases up to 0.1.0 wrote no description. That is enough
for a reader, not for tooling that maps codes across datasets or builds features from
descriptions: vital codes are column names (VITALS//PERIODIC//HEARTRATE), lab names are
site picklist abbreviations (Hgb, -polys, WBC x 1000), and vocabulary-based enrichment
(OHDSI Athena) cannot resolve either. So every code now gets the documented meaning of what it
encodes, through three routes, with the source of each description recorded:
| Code family | Route | Source of the text |
|---|---|---|
LAB//RESULT//…, LAB//SPECIMEN_DRAWN//… |
src/eICU_MEDS/metadata/lab_descriptions.csv, joined by _metadata on the raw labname (a partial match, so one row covers every unit variant); pre-MEDS writes it as lab_descriptions.parquet |
per row, in the table's source column: the WeavEHR concept the lab name maps to (aidh-ms/WeavEHR configs/datasets/eicu-crd/2.0/mappings, MIT, commit 210a539), the label of the MIMIC-IV lab item mapped to the same concept (mimic-code d_labitems_to_loinc.csv, MIT), the canonical column in eicu-code pivoted-lab.sql / pivoted-bg.sql (MIT), or, for the long tail, a plain expansion of the picklist name marked expansion |
literal codes: the 26 VITALS//…, ICU_ADMISSION_WEIGHT/_HEIGHT, ICU_DISCHARGE_WEIGHT, SUBJECT_WEIGHT_AT_INFUSION, INFUSION_DRUG, CAREPLAN_EOL, MEDS_BIRTH, MEDS_DEATH |
src/eICU_MEDS/metadata/static_code_descriptions.csv, filled into the finished codes.parquet by the ETL's last step (code_descriptions.apply_static_descriptions) |
per row: the column description in the eICU-CRD table documentation, the WeavEHR concept and unit, and the MIMIC-IV d_items label of the item WeavEHR maps to the same concept (open MIMIC-IV demo, ODbL); expansion where only the abbreviation is documented (ST1–3, SVR/SVRI, PVR/PVRI, cardiac input) |
| every other family (patient events, diagnoses, admission diagnoses, allergies, care plan items, intake/output, medications, nursing assessment, nursing care, nurse charting, past history, physical exam, respiratory charting, treatments) | _metadata: _self: description: templates in configs/event_configs.yaml, evaluated per event |
the code's own components, named after the eICU-CRD column they come from (patient.unitAdmitSource, diagnosis.diagnosisString, …) |
The lab table carries descriptions only. eICU records no LOINC code for its lab names, so the
ETL writes no LOINC parent for them; the lab-name to LOINC crosswalk is part of suMEDS's
versioned ontology data and is applied after extraction (see Enriching code metadata with suMEDS).
Diagnoses keep their ICD parents (below), which come from eICU's own icd9code column.
The lab table lists only lab names that are already public: the 147 in the open eICU-CRD demo
(ODbL) and one more in eicu-code (MIT). It ships nothing
that exists only in the credentialed release. A lab name outside the table gets a generic
description from the ETL's last step, built from the code itself, for example
Lab result (eICU lab.labName '<labname>').
Why three routes: MEDS-Extract attaches _metadata by joining on the code's components, so
a literal code has none to join on, and the pre-existing metadata/codes.parquet it documents
for that case is not read by the standard extraction pipeline (extract_code_metadata reads
its prior metadata stage's output, split_and_shard_subjects, which writes no
codes.parquet). The post-pipeline fill only ever writes a description where the pipeline
left null, never extends the vocabulary, and is idempotent.
On the demo (eICU-CRD demo 2.0.1) every one of the 8,122 codes is described: 294 lab codes, 34 literal codes, and 7,794 component-coded codes. Event data is untouched: per-code event counts are identical to a build without this metadata.
On the full release (eICU-CRD 2.0) every one of the 15,528 codes is described: 316 lab codes
(a RESULT and a SPECIMEN_DRAWN code for each of the 158 lab names; 148 names are in the
table and the other 10 get the generic description), 34 literal codes, and 15,178
component-coded codes. Every code in the data is in codes.parquet, and the file validates
against meds.CodeMetadataSchema.
MEDS 0.4 makes description optional, so consumers must still not rely on it being
non-null for datasets built with older releases.
ICD parent codes for diagnoses are the other piece of code metadata: each DIAGNOSIS//...
code gets ICD9CM/... and/or ICD10CM/... parent codes from the icd9code column of
diagnosis (via the dx_icd_map table built in pre-MEDS). In the demo, 860 of the 1,091
diagnosis codes have one; in the full release, 3,129 of the 3,933. parent_codes is written
sorted, so that two runs over the same data write the same file.
Enriching code metadata with suMEDS
The ETL writes what eICU itself records. Links to external vocabularies that eICU does not
record, and parents among eICU's own codes, are added by
suMEDS with the rules file shipped in this package,
src/eICU_MEDS/sumeds_rules.yaml. The crosswalk tables and ontology packs come from suMEDS's
versioned ontology data (sumeds-ontologies, pinned release), so this repository does not ship
them, and no Athena download or LOINC account is needed.
To enrich as part of the ETL, install the sumeds extra and turn on do_enrich:
pip install "eICU-MEDS[sumeds]"
MEDS_extract-eICU root_output_dir=data/eicu_meds do_enrich=True
The last step then rewrites MEDS_output/metadata/codes.parquet in place. The run checks that
suMEDS is installed before it starts. If the enrichment itself fails, for example without network
access, the ETL's codes.parquet is left as it was. Enrichment is off by default because suMEDS
is an extra dependency, because it downloads its ontology data from GitHub on first use (cached
under ~/.cache/sumeds; on a machine without internet access, point SUMEDS_ONTOLOGY_SOURCE at a
local copy of the pinned sumeds-ontologies release), and because the default output then holds
only what eICU records.
To enrich an existing output instead, run suMEDS on its own. Given the same codes.parquet, it
writes the same table as do_enrich=True:
pip install "sumeds>=0.4"
suMEDS-enrich $MEDS_DIR/metadata/codes.parquet -o codes_enriched.parquet \
--rules "$(python -c 'from importlib.resources import files; print(files("eICU_MEDS") / "sumeds_rules.yaml")')"
This needs suMEDS 0.4 or later, the first release with ontology rules. The rules add:
- LOINC for lab results (
eicu-lab-loinc, a crosswalk):LAB//RESULT//{labname}//{unit}getsLOINC//<code>inparent_codes, plusvocabulary_idandconcept_code, for the 50 lab names in the crosswalk tableeicu/lab_loinc, each validated against the LOINC pack. The links are an inference across two curated mappings (eICU name → WeavEHR concept ← MIMIC-IV item with its LOINC code in mimic-coded_labitems_to_loinc.csv), so the LOINC code inherits the MIMIC item's specimen (serum/plasma versus blood); the table records both ends. - Parents among eICU codes (
eicu-diagnosis-paths,eicu-admission-diagnosis-paths,eicu-treatment-paths, hierarchy rules): a|-separated path gets the nearest shorter path that is itself a code, e.g.TREATMENT//ENTERED//a|b|cgetsTREATMENT//ENTERED//a|b. On the full release that adds 2,929 diagnosis and 2,096 treatment parents; admission diagnosis paths are recorded only as leaves, so that rule adds none today.
The ETL alone no longer emits LOINC parents for lab codes (builds of main after #27 wrote
LOINC/<code> for the same 50 lab names), and it never emitted parents among eICU codes:
metadata/codes.parquet from the ETL has ICD parents for diagnoses only, and suMEDS supplies
the rest: it links the same 50 lab codes to the same LOINC codes the ETL used to write, and it
never removes or rewrites the ETL's own parents or descriptions.
Which eICU tables are extracted
eICU-CRD v2.0 ships 31 tables. This pipeline reads 22 of them. The rest are excluded deliberately — the reasoning is recorded here rather than in a code comment, because "this table is missing" is otherwise indistinguishable from an oversight.
Extracted: patient, hospital (joined for site attributes), admissionDx,
allergy, carePlanEOL, carePlanGeneral, carePlanGoal,
carePlanInfectiousDisease, diagnosis, infusionDrug, intakeOutput, lab, medication,
nurseAssessment, nurseCare, nurseCharting, pastHistory, physicalExam, respiratoryCharting, treatment, vitalAperiodic,
vitalPeriodic.
Excluded — deliberate, on the merits:
| Table | Rows | Why not |
|---|---|---|
admissionDrug |
874,920 | Documented as "extremely infrequently used". |
apacheApsVar |
171,177 | Inputs to the APACHE score. We prefer the raw measurements they were computed from. |
apachePatientResult |
297,064 | Pre-computed APACHE scores and predictions — derived values, not observations. |
apachePredVar |
171,177 | Further APACHE inputs; same reasoning. |
carePlanCareProvider |
502,765 | Cannot be linked to the specific care-plan entries it describes, and its offsets record when a provider was entered into the plan rather than any clinical event. |
customLab |
1,082 | Documentation is very sparse, and it holds only the lab measurements that could not be mapped to the standard set in lab. |
microLab |
16,996 | Time leakage: culture-taken time is not culture-result time, so a model would see organism/sensitivity results before they could exist. Also documented as poorly populated. |
note |
2,254,179 | Largely duplicative of the structured tables — narrative notes were mostly removed for PHI reasons. |
Excluded — not yet done, not on the merits. These carry real clinical signal and
were stubbed out but never finished (the original config shipped commented-out blocks
for them marked NOT YET DONE, because their cell-label/value structure needs a code
scheme of its own):
| Table | Rows | Contains |
|---|---|---|
respiratoryCare |
865,381 | Ventilator settings and airway management. |
MEDS-transforms settings
If you want to convert a large dataset, you can use parallelization with MEDS-transforms (the MEDS-transformation step that takes the longest).
Local parallelization uses the hydra-joblib-launcher package, which is installed as a dependency of
eICU-MEDS. You can set the number of workers as an environment variable:
export N_WORKERS=8
Size N_WORKERS to memory, not cores: each worker is a separate process with its own working
set. On the full release, N_WORKERS=4 exhausted a 24 GB laptop, with each of the four workers
holding 7.5 to 8 GB during split_and_shard_subjects. That is a metadata stage, so every worker
repeats the whole computation rather than taking a share of it. The same build run serially
(N_WORKERS unset, polars limited to four threads with POLARS_MAX_THREADS=4) peaked at 4.8 GB
and took 20 minutes on a 10-core machine.
The number of subjects per shard is fixed at 1,000 in the split_and_shard_subjects stage of
src/eICU_MEDS/configs/ETL.yaml; no environment variable or command-line option changes it. Other MEDS ETLs
do the same (MIMIC-IV fixes it in its spec's etl: block): MEDS-Extract treats shard size as a property of
the dataset, while worker counts belong to the machine running it. To use a different shard size, edit that
file in a local checkout (see Development).
Development
Contributors should use uv to set up a development environment from the
lockfile:
git clone https://github.com/Medical-Event-Data-Standard/eICU_MEDS.git
cd eICU_MEDS
uv sync --group dev
uv run pre-commit install
uv run pytest src/ tests/ --doctest-modules
The end-to-end test (tests/e2e_demo_test.py) downloads the public eICU demo from PhysioNet, so it is
slow on a first run. DEVELOPMENT.md covers testing, running the ETL on the full release,
and cutting a release with uv version --bump.
Citation
If you use this code in your research, please cite the following:
@article{PhysioNet-eicu-crd-2.0,
author = {Pollard, Tom and Johnson, Alistair and Raffa, Jesse and Celi, Leo Anthony and Badawi, Omar and Mark, Roger},
title = {{eICU Collaborative Research Database}},
journal = {{PhysioNet}},
year = {2019},
month = apr,
note = {Version 2.0},
doi = {10.13026/C2WM1R},
url = {https://doi.org/10.13026/C2WM1R}
}
@article{Pollard2018-ln,
title = "The {eICU} Collaborative Research Database, a freely available
multi-center database for critical care research",
author = "Pollard, Tom J and Johnson, Alistair E W and Raffa, Jesse D and
Celi, Leo A and Mark, Roger G and Badawi, Omar",
journal = "Sci. Data",
publisher = "Springer Science and Business Media LLC",
volume = 5,
number = 1,
pages = "180178",
month = sep,
year = 2018,
copyright = "https://creativecommons.org/licenses/by/4.0",
language = "en"
}
@software{McDermott_eICU_MEDS_eICU_MEDS,
author = {McDermott, Matthew and Zhu, Mingcheng and van de Water, Robin Philippus},
license = {MIT},
title = {{eICU\_MEDS: eICU MEDS Extraction ETL}},
url = {https://github.com/Medical-Event-Data-Standard/eICU_MEDS/}
}
Metadata
Release files for eICU-MEDS 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| eicu_meds-0.2.0.tar.gz | 73.8 kB | With provenance | Details for eicu_meds-0.2.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| eicu_meds-0.2.0-py3-none-any.whl | Python 3 | none | any | Details for eicu_meds-0.2.0-py3-none-any.whl |
Total release size: 118.2 kB
Release files / eicu_meds-0.2.0.tar.gz
| Download URL | eicu_meds-0.2.0.tar.gz |
|---|---|
| Size | 73.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b1a0f736f376b24422cee7002e6c3e06ca9fac4a1e635cc8b2fa866cbaaa3b2f
|
|
BLAKE2b-256 checksum How to use checksums |
06d7bc3dd73fc5accb2cfd959df84214cefc5d774bf2481fed60fe99307eab6c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 3, 2026.
Transparency logRelease files / eicu_meds-0.2.0-py3-none-any.whl
| Download URL | eicu_meds-0.2.0-py3-none-any.whl |
|---|---|
| Size | 44.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a3debb9753e42c7a8b344098f88c202748772498c996bb480ad176ce90aee2fe
|
|
BLAKE2b-256 checksum How to use checksums |
e4a62154a0c28ad29fb1f8c20e66839f17c5a1e62bec2ab166b0c1d4e1d52217
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 3, 2026.
Transparency logSecurity for eICU-MEDS 0.2.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
Both files in this release have been uploaded with provenance metadata.
Attestation for eicu_meds-0.2.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 3, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.