ALOTT-MEDS
ALOTT (ALarms, Outcomes Telemetry with Timing) is a pilot bedside-EMR database from two hospitals, collected to support algorithms that predict emergency response team events. It pairs bedside telemetry from 270 beds (alarms, monitor measurements and waveforms) with electronic medical record data: admissions, diagnoses, ICU stays and bed moves, labs, orders, medications and nursing flowsheets. This pipeline extracts the EMR tables of ALOTT (from PhysioNet, https://physionet.org/content/alott/) into the MEDS format. It is built the same way as MIMIC_IV_MEDS: one declarative MEDS-Extract spec, no Python.
Usage:
pip install git+https://github.com/rvandewater/ALOTT_MEDS
export DATASET_DOWNLOAD_USERNAME=$PHYSIONET_USERNAME
export DATASET_DOWNLOAD_PASSWORD=$PHYSIONET_PASSWORD
meds-extract-run spec=ALOTT output_dir=$MEDS_OUTPUT_DIR
That downloads only the emr-datasets/ folder of the ALOTT 1.0.0 release (the telemetry is
skipped) into $MEDS_OUTPUT_DIR/.meds_extract_run/raw_input and runs the full MEDS-Extract
pipeline, writing data/ and metadata/ to $MEDS_OUTPUT_DIR. Files that already exist and
verify against PhysioNet's checksums are skipped, so an interrupted download resumes. Pass
download_dest_dir=$RAW_INPUT_DIR to keep the raw data somewhere durable.
ALOTT is a credentialed release: the PhysioNet account must have signed the ALOTT data use agreement.
To reuse a download you already have, point input_dir at the directory that contains
emr-datasets/:
meds-extract-run spec=ALOTT output_dir=$MEDS_OUTPUT_DIR do_download=false input_dir=$RAW_INPUT_DIR
Run meds-extract-run --help for the full set of arguments.
Configuration
The whole pipeline is one file,
src/ALOTT_MEDS/event_configs.yaml, written in MESSY
(MEDS-Extract Specification Syntax YAML) and registered under the MEDS_extract.pipelines
entry-point group as ALOTT. That registration is what makes spec=ALOTT work from anywhere
and what stamps the output's metadata/dataset.json with
<ALOTT release>:<this package's version>. The file holds:
- a
sources:block pointing at the PhysioNet release, restricted toemr-datasets/*; - an
etl:block with the run's few knobs; - one block per raw EMR table describing the events extracted from it.
Timestamps
ALOTT shifts each patient's dates by a random -180..180 days but keeps the time of day. Most
tables store each timestamp as one shifted %Y-%m-%d %H:%M:%S column. Labs and orders carry
only a shifted date, and medication start and end times are always 00:00:00, i.e. dates
too. Those events are placed at the end of that day (23:59:59): midnight would make a
result or a new medication visible before it existed, which leaks the future into any
prediction made later that day. Same-day lab orders and results therefore share a time.
Medication administrations keep their recorded time of day. A row with a null timestamp
produces no event.
Absolute dates are shifted per patient, so only differences within a subject are meaningful.
IDs
aMRN is the MEDS subject_id; the encounter key aCSN is carried as hadm_id. Lab and
order results use the resulting encounter, and orders the ordering one. The release
writes the string nan for an unresulted encounter; it is cast leniently, so it becomes a
null and hadm_id stays Int64.
Codes
Every code is FAMILY//..., from general to specific, so a prefix selects a group (all
labs, one lab panel, one drug). Where a table records both an order and its outcome, the
second component says which: ORDERED or RESULT, START or STOP, or MAR
(Medication Administration Record: the bedside log of each dose given, held or refused).
UNK stands for a null component that must not drop the row (see
Null handling).
| Code | Table | Time | Value and extra columns |
|---|---|---|---|
HOSPITAL_ADMISSION//<admission type>//<source> |
admission | admission | reason for visit in text_value |
HOSPITAL_DISCHARGE//<destination> |
admission | discharge | |
DIAGNOSIS//ICD//10//<ICD-10-CM code> |
admission | discharge | diagnosis text; diagnosis_rank PRIMARY or SECONDARY |
<FIELD>//<value> |
demographics | static | FIELD is GENDER, MARITAL_STATUS, RACE, ETHNICITY, LANGUAGE or BLOOD_TYPE |
ALLERGY//<allergen> |
allergy | static | reaction in text_value |
FLOWSHEET//<FLO_MEAS_ID> |
flowsheet | recorded | reading or score; flow_type |
ICU_ADMISSION, ICU_DISCHARGE |
icu | start, end | |
TRANSFER |
location | start | |
MEDICATION//START//<drug> |
medications | start date, 23:59:59 | ordered dose (raw text if a range); dose_unit, frequency |
MEDICATION//STOP//<drug> |
medications | end date, 23:59:59 | |
MEDICATION//MAR//<drug>//<action> |
medications | administration | given dose; dose_unit, route |
LAB//ORDERED//<PROC_ID> |
labs | order date, 23:59:59 | |
LAB//RESULT//<PROC_ID>//<component> |
labs | result date, 23:59:59 | result; order_status |
ORDER//ORDERED//<order type>//<PROC_ID> |
orders | order date, 23:59:59 | order_status |
ORDER//RESULT//<order type>//<PROC_ID> |
orders | result date, 23:59:59 | result; order_status |
codes.parquet carries a description for flowsheet, lab and order codes, taken from the
release's display names.
Null handling
A null component of a composite code drops the row under MEDS-Extract 0.7. Components are
therefore coalesced with ?? 'UNK' wherever a null must not drop the row (admission type and
source, discharge destination, lab component, order type, medication administration action).
The rest are deliberately left uncoalesced. In the release, the code columns of
flowsheets, labs, orders and allergies are never null, and MEDICATION is null in 10 of
12,698,867 rows, so a coalesce would add nothing. A missing ICD-10 code or demographic
produces no event rather than an UNK category, because a missing value is not an observed
one.
Diagnoses
The primary and secondary ICD-10 codes on each visit become DIAGNOSIS//ICD//10//<code>
events at discharge time, with diagnosis_rank set to PRIMARY or SECONDARY. About 4% of
cells list up to four codes separated by a comma and a space; each code becomes its own event, carrying the
cell's full diagnosis text. No
parent_codes metadata is attached: the same code occurs as both primary and secondary, and
MEDS-Extract rejects one code produced by two code templates.
DIAGNOSIS//ICD//10//<code> maps to ICD10CM/<code> directly.
Other tables
- ICU stays and bed moves carry only their start and end times in the release (no unit,
room or bed), so they become bare
ICU_ADMISSION,ICU_DISCHARGEandTRANSFERevents. - Demographics and allergies carry no time in the release and are static events.
- Flowsheet, lab and order-result values are free text. The numeric reading is kept where
it parses; scored flowsheet items charted as
<score>--><label>(e.g.-1-->Drowsy) keep their score. The raw string goes totext_valueunless it is just the number. Epic's nonnumeric sentinel9999999never becomes a numeric value. - Medications: each row of the release is one administration and repeats its order's
start and end, so an order yields one
START, oneSTOPand oneMARevent per administration. - Orders hold every order type except labs; roughly half carry a single result.
- Birth and death: the release has no birth date, age or death time, so there are no
MEDS_BIRTHorMEDS_DEATHevents. - Not extracted: the telemetry (alarms, 2-second measurements, waveforms; per-admission
files keyed by file name, far larger than the EMR),
social_hx(no event times and unlabeled Epic category codes), and the medication order date.
Validation against the release
The spec was first written from the authors' release code (Carescape) and did not run on the published files. Profiling the 1.0.0 EMR CSVs (value shapes and null counts only, never values) showed what had to change:
- Tables are lowercase (
admission,labs, ...) rather thanPatient,Labs, ...; the keys areaMRNandaCSN, notcsIDandCS_PAT_ENC_CSN_ID. - Each timestamp is one already-shifted column rather than a date plus an
HH:MM:SScolumn. Labs and orders keep only the date (see Timestamps). icuandlocationhave no department, event type, room or bed columns.resulting_aCSNholds the stringnanfor unresulted rows.- 1,536 ICD-10 codes occur as both primary and secondary diagnoses, and some cells list several codes (see Diagnoses). The synthetic test covers both.
- Medication start and end times are always midnight, and
orderscarries results of its own (it holds no lab orders).
All ten CSVs are valid UTF-8. On the full 1.0.0 EMR tables (6.3 GB of CSVs read),
meds-extract-run with MEDS-Extract 0.7.1 finishes in about 90 seconds on a laptop with about
6.5 GB peak memory, producing 52.6M events for 18,472 subjects. Fewer lab, order and
medication start/stop events come out than raw rows because identical events are merged: lab
and order times have day resolution, and the medication table repeats an order's start and
end on every administration row.
MEDS-transforms settings
If you want to convert a large dataset, you can parallelize the MEDS-transforms stages (the MEDS-transformation step that takes the longest).
Using local parallelization with the hydra-joblib-launcher package:
pip install hydra-joblib-launcher --upgrade
Then write a stage-runner file and pass it to the run:
# runner.yaml
parallelize:
n_workers: 8
launcher: joblib
meds-extract-run spec=ALOTT output_dir=$MEDS_OUTPUT_DIR stage_runner_fp=runner.yaml
The number of subjects per shard is n_subjects_per_shard in the spec's etl: block
(1000 by default); raise it to cut the parallelization overhead.
Development
uv sync --group dev
uv run pytest tests/
uv run pre-commit run --all-files
A release bumps the version in pyproject.toml with uv version --bump, commits it and pushes
a tag of that exact version, which publishes to PyPI and creates the GitHub release. See RELEASING.md for choosing the
version, the one-time PyPI setup and recovering from a failed release.
ALOTT has no open demo, so CI runs the spec end to end over a small synthetic input
generated in tests/e2e_synthetic_test.py. That checks the
spec's mechanics, not its agreement with the real release. Never commit raw ALOTT data or
MEDS output derived from it.
Citation
Please cite the following original dataset when using ALOTT:
@article{PhysioNet-alott-1.0.0,
author = {Lawrence, John and Rayo, Mike and Huerta, Timothy},
title = {{ALarms, Outcomes Telemetry with Timing (ALOTT): a Bedside-EMR Database}},
journal = {{PhysioNet}},
year = {2025},
month = mar,
note = {Version 1.0.0},
doi = {10.13026/sbq5-dy17},
url = {https://doi.org/10.13026/sbq5-dy17}
}
Also cite the ETL framework used to extract the dataset:
@software{van_de_Water_ALOTT_MEDS_ETL_2025,
author = {van de Water, Robin Philippus},
license = {MIT},
month = apr,
title = {{ALOTT\_MEDS ETL}},
url = {https://github.com/rvandewater/ALOTT_MEDS},
year = {2025}
}
For citing MEDS in general:
@article{mcdermott2026meds,
title={MEDS—An Emerging Data Standard and Ecosystem for Health AI Research},
author={McDermott, Matthew BA and Steinberg, Ethan and Fries, Jason A and van de Water, Robin P and Pang, Chao and Rockenschaub, Patrick and Renc, Pawel and Oh, Jungwoo and Stankevi{\v{c}}i{\=u}t{\.e}, Kamil{\.e} and Xu, Justin and others},
journal={NEJM AI},
volume={3},
number={6},
pages={AIra2501253},
year={2026},
publisher={Massachusetts Medical Society}
}
Metadata
Release files for ALOTT-MEDS 0.0.1
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 | |
|---|---|---|---|---|
| alott_meds-0.0.1.tar.gz | 18.0 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| alott_meds-0.0.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 31.3 kB
Release files / alott_meds-0.0.1.tar.gz
| Download URL | alott_meds-0.0.1.tar.gz |
|---|---|
| Size | 18.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b6110566d0a5f50a0cd9c03335a81dba776dcb2a1d4e7f33c9cb5d969a987a62
|
|
BLAKE2b-256 checksum How to use checksums |
c10316f1b5ef5a7343a18d1eb10be8ad8d0ada26094e6a871a055fc5282258fb
|
| 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 Oct 27, 2026.
Transparency logRelease files / alott_meds-0.0.1-py3-none-any.whl
| Download URL | alott_meds-0.0.1-py3-none-any.whl |
|---|---|
| Size | 13.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0d4fefc4d547edaa803d234c90ba363a3977636d16b5637cc1a1a6cdc5e5547f
|
|
BLAKE2b-256 checksum How to use checksums |
7b63bad13c8c882cd03659f9dc8bb2d86d3a85ba6f23665de8dd81162da49ec9
|
| 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 Oct 27, 2026.
Transparency logSecurity for ALOTT-MEDS 0.0.1
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
All 2 files in this release have been uploaded with provenance metadata.
Attestation for alott_meds-0.0.1.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 Oct 27, 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.