Getting started

Access CDISC ADaM and SDTM test datasets in Python

Datasets are module attributes, lazy-loaded from parquet.

Collections

Module Standard Source Datasets
pharmadata.pharmaverseadam ADaM pharmaverseadam 30
pharmadata.pharmaversesdtm SDTM pharmaversesdtm 64
pharmadata.cdiscpilotadam ADaM CDISC pilot 12
pharmadata.cdiscpilotsdtm SDTM CDISC pilot 31

Install

pip install pharmadata

Usage

import polars as pl
from pharmadata import pharmaverseadam as adam, pharmaversesdtm as sdtm
adam.list_datasets()
adam.meta_tables()
adam.meta_columns()
adam.meta_specs()
adam_dict = adam.to_dict()
adsl = adam.adsl
adsl_meta = adam.adsl_meta
adsl_meta.column_names
adsl_meta.column_labels
adsl_meta.column_names_to_labels
adsl_meta.number_rows
adsl_meta.number_columns
adsl_meta.file_label
adsl_meta.file_encoding
adsl.head()
shape: (5, 55)
STUDYIDUSUBJIDSUBJIDSITEIDCOUNTRYRFSTDTCRFENDTCRFXSTDTCRFXENDTCRFPENDTCSCRFDTFRVDTDTHDTCDTHADYDTHFLLDDTHELDLDDTHGR1DTH30FLDTHA30FLDTHDOMDTHB30FLREGION1DMDTCDMDYAGEAGEUAGEGR1SEXRACERACEGR1ETHNICSAFFLARMARMCDACTARMACTARMCDTRT01PTRT01ATRTSDTTRTSDTMTRTSTMFTRTEDTTRTEDTMTRTETMFEOSSTTEOSDTRFICDTCRANDDTLSTALVDTTRTDURDDTHDTDTHDTFDTHCAUSDTHCGR1BRTHDTC
strstrstrstrstrstrstrstrstrstrdatedatestrf64strf64strstrstrstrstrstrstrf64f64strstrstrstrstrstrstrstrstrstrstrstrstrdatedatetime[μs, UTC]strdatedatetime[μs, UTC]strstrdatestrdatedatef64datestrstrstrstr
"CDISCPILOT01""01-701-1015""1015""701""USA""2014-01-02""2014-07-02""2014-01-02""2014-07-02""2014-07-02T11:45"nullnullnullnullnullnullnullnullnullnullnull"NA""2013-12-26"-7.063.0"YEARS""18-64""F""WHITE""White""HISPANIC OR LATINO""Y""Placebo""Pbo""Placebo""Pbo""Placebo""Placebo"2014-01-022014-01-02 00:00:00 UTC"H"2014-07-022014-07-02 23:59:59 UTC"H""COMPLETED"2014-07-02null2014-01-022014-07-02182.0nullnullnullnull"1950-12-26"
"CDISCPILOT01""01-701-1023""1023""701""USA""2012-08-05""2012-09-02""2012-08-05""2012-09-01""2013-02-18"null2013-02-18nullnullnullnullnullnullnullnullnull"NA""2012-07-22"-14.064.0"YEARS""18-64""M""WHITE""White""HISPANIC OR LATINO""Y""Placebo""Pbo""Placebo""Pbo""Placebo""Placebo"2012-08-052012-08-05 00:00:00 UTC"H"2012-09-012012-09-01 23:59:59 UTC"H""DISCONTINUED"2012-09-02null2012-08-052012-09-0228.0nullnullnullnull"1948-07-22"
"CDISCPILOT01""01-701-1028""1028""701""USA""2013-07-19""2014-01-14""2013-07-19""2014-01-14""2014-01-14T11:10"nullnullnullnullnullnullnullnullnullnullnull"NA""2013-07-11"-8.071.0"YEARS"">64""M""WHITE""White""NOT HISPANIC OR LATINO""Y""Xanomeline High Dose""Xan_Hi""Xanomeline High Dose""Xan_Hi""Xanomeline High Dose""Xanomeline High Dose"2013-07-192013-07-19 00:00:00 UTC"H"2014-01-142014-01-14 23:59:59 UTC"H""COMPLETED"2014-01-14null2013-07-192014-01-14180.0nullnullnullnull"1942-07-11"
"CDISCPILOT01""01-701-1033""1033""701""USA""2014-03-18""2014-04-14""2014-03-18""2014-03-31""2014-09-15"null2014-09-15nullnullnullnullnullnullnullnullnull"NA""2014-03-10"-8.074.0"YEARS"">64""M""WHITE""White""NOT HISPANIC OR LATINO""Y""Xanomeline Low Dose""Xan_Lo""Xanomeline Low Dose""Xan_Lo""Xanomeline Low Dose""Xanomeline Low Dose"2014-03-182014-03-18 00:00:00 UTC"H"2014-03-312014-03-31 23:59:59 UTC"H""DISCONTINUED"2014-04-14null2014-03-182014-04-1414.0nullnullnullnull"1940-03-10"
"CDISCPILOT01""01-701-1034""1034""701""USA""2014-07-01""2014-12-30""2014-07-01""2014-12-30""2014-12-30T09:50"nullnullnullnullnullnullnullnullnullnullnull"NA""2014-06-24"-7.077.0"YEARS"">64""F""WHITE""White""NOT HISPANIC OR LATINO""Y""Xanomeline High Dose""Xan_Hi""Xanomeline High Dose""Xan_Hi""Xanomeline High Dose""Xanomeline High Dose"2014-07-012014-07-01 00:00:00 UTC"H"2014-12-302014-12-30 23:59:59 UTC"H""COMPLETED"2014-12-30null2014-07-012014-12-30183.0nullnullnullnull"1937-06-24"

Format

from pharmadata import set_output_pandas, set_output_polars, output_format
set_output_pandas()
dm = sdtm.dm
print(type(dm))
set_output_polars()
dm = sdtm.dm
print(type(dm))
<class 'pandas.DataFrame'>
<class 'polars.dataframe.frame.DataFrame'>

set_output_pandas() / set_output_polars() switch globally; output_format() is a context manager.

with output_format("pandas"):
    adsl_pd = adam.adsl

print(type(adsl_pd))
<class 'pandas.DataFrame'>

Validate by pointblank

import pointblank as pb
# pb.validate_adam(adsl, "ADSL")
pb.validate_adam_structure(adsl, "ADSL")
{'dataset': 'ADSL',
 'dataset_class': 'ADSL',
 'valid': True,
 'missing_required': [],
 'missing_conditional': [],
 'unknown_variables': [],
 'population_flags_found': ['SAFFL'],
 'issues': []}

Polars Examples

adsl.select(["STUDYID", "USUBJID", "AGE", "SEX", "TRT01A"]).head()
shape: (5, 5)
STUDYIDUSUBJIDAGESEXTRT01A
strstrf64strstr
"CDISCPILOT01""01-701-1015"63.0"F""Placebo"
"CDISCPILOT01""01-701-1023"64.0"M""Placebo"
"CDISCPILOT01""01-701-1028"71.0"M""Xanomeline High Dose"
"CDISCPILOT01""01-701-1033"74.0"M""Xanomeline Low Dose"
"CDISCPILOT01""01-701-1034"77.0"F""Xanomeline High Dose"
adsl.filter((pl.col("AGE") >= 75) & (pl.col("SEX") == "F")).select(
    ["USUBJID", "AGE", "SEX", "TRT01A"]
).head()
shape: (5, 4)
USUBJIDAGESEXTRT01A
strf64strstr
"01-701-1034"77.0"F""Xanomeline High Dose"
"01-701-1047"85.0"F""Placebo"
"01-701-1111"81.0"F""Xanomeline Low Dose"
"01-701-1133"81.0"F""Xanomeline High Dose"
"01-701-1146"75.0"F""Xanomeline High Dose"
adsl.filter(pl.col("TRT01A") != "Screen Failure").group_by("TRT01A").agg(
    pl.col("AGE").mean().round(1).alias("mean_age"),
    pl.len().alias("n"),
).sort("TRT01A")
shape: (3, 3)
TRT01Amean_agen
strf64u32
"Placebo"75.286
"Xanomeline High Dose"73.872
"Xanomeline Low Dose"76.096

Read parquet directly

  • Dataset label in schema metadata
  • Column labels in field metadata.

Both are bytes, decode to str

from importlib import resources

import pyarrow.parquet as pq

path = resources.files("pharmadata") / "_data" / "pharmaverseadam" / "adsl.parquet"
schema = pq.ParquetFile(path).schema_arrow

print((schema.metadata or {}).get(b"label", b"").decode())
print({
    name: (schema.field(name).metadata or {}).get(b"label", b"").decode()
    for name in schema.names[:3]
})
Subject Level Analysis
{'STUDYID': 'Study Identifier', 'USUBJID': 'Unique Subject Identifier', 'SUBJID': 'Subject Identifier for the Study'}
pl.from_arrow(pq.read_table(path, columns=schema.names[:6])).head(5)
shape: (5, 6)
STUDYIDUSUBJIDSUBJIDSITEIDCOUNTRYRFSTDTC
strstrstrstrstrstr
"CDISCPILOT01""01-701-1015""1015""701""USA""2014-01-02"
"CDISCPILOT01""01-701-1023""1023""701""USA""2012-08-05"
"CDISCPILOT01""01-701-1028""1028""701""USA""2013-07-19"
"CDISCPILOT01""01-701-1033""1033""701""USA""2014-03-18"
"CDISCPILOT01""01-701-1034""1034""701""USA""2014-07-01"