Metadata-driven wrappers over admiral for the three derivations that get rewritten as study-specific code on every study:
| Function | Does | Replaces the SAS |
|---|---|---|
grade_lab() |
Lab toxicity grades against published NCI-CTCAE / DAIDS criteria |
%LABGRADE / %CTCAE nested IF/ELSE cascade |
collapse_ae_episodes() |
Collapses AE records into episodes by interval merging |
%AE_EPISODE RETAIN _prev_end DATA step |
derive_pop_flags() |
Population flags from a rules table |
%POPFLAG IF trtsdt NE . THEN saffl = 'Y';
|
Supporting exports: grading_table() and pop_rules() validate the metadata and print it; sas_note() prints the SAS idiom each derivation replaces.
Every function returns a plain tibble, so the result hands straight back to admiral, rtables or xportr. No study-specific parameter, threshold or flag name is hardcoded anywhere in the package.
# from source
install.packages("admiralease", repos = NULL, type = "source")Runs as-is: the inputs are the fixtures shipped with the package.
library(admiralease)
ex <- function(f) system.file("extdata", f, package = "admiralease")
# 1. Lab toxicity grading -----------------------------------------------
# Default: NCI-CTCAE v5 *laboratory* criteria (admiral::atoxgr_criteria_ctcv5).
# ATOXDSCL/ATOXDSCH must already hold the criteria term for each record.
adlb <- utils::read.csv(ex("adlb_example.csv"))
graded <- grade_lab(adlb)
graded[, c("PARAMCD", "AVAL", "ATOXGRL", "ATOXGRH", "ATOXGR")]
#> PARAMCD AVAL ATOXGRL ATOXGRH ATOXGR
#> 1 ALT 20.0 NA 0 0
#> 2 ALT 120.0 NA 2 2
#> 3 ALT NA NA NA NA <- missing stays missing, not "0"
#> 4 POTAS 5.4 0 0 0 <- exactly on the threshold: not graded
#> 5 POTAS 5.8 0 2 2
#> 6 POTAS 3.2 2 0 -2 <- low toxicity carried as negative
#> 7 POTAS 1.9 4 0 -4
#> 8 SODIUM 128.0 3 0 -3
#> 9 HGB 6.0 NA NA NA <- mmol/L, criterion checks g/L
#> 10 PLAT 400.0 0 NA 0
#> 11 PLAT 60.0 2 NA -2
#> 12 BILI 40.0 NA 2 2
#> 13 CREAT 130.0 NA 2 2
#> 14 ALB 30.0 1 NA -1
#> 15 HGBC 9.0 NA NA NA
#> 16 PHOS 0.7 NA NA NA
#> 17 ANISO 1.0 NA NA NA <- term not in the table: NA, not "0"
# The criteria sets differ, and they differ where the standards differ.
data.frame(
PARAMCD = adlb$PARAMCD,
ctcv4 = grade_lab(adlb, "ctcv4")$ATOXGR,
ctcv5 = grade_lab(adlb, "ctcv5")$ATOXGR,
uscv = grade_lab(adlb, "ctcv5_uscv")$ATOXGR
)[c(14, 15, 16), ]
#> PARAMCD ctcv4 ctcv5 uscv
#> 14 ALB -1 -1 NA <- g/L: no US-conventional criterion matches
#> 15 HGBC NA NA -2 <- g/dL: only the US-conventional table grades it
#> 16 PHOS -2 NA NA <- Hypophosphatemia was dropped in CTCAE v5
# 2. AE episodes ---------------------------------------------------------
adae <- utils::read.csv(ex("adae_example.csv"))
collapse_ae_episodes(adae, gap_days = 1)
#> # A tibble: 7 x 9
#> USUBJID AEDECOD EPISODE ASTDT AENDT AESEV AEREL NRECORD ONGOING
#> AE01-001 ERYTHEMA 1 2021-01-05 2021-01-15 MODERATE POSSIBLE 2 FALSE
#> AE01-001 HEADACHE 1 2021-03-01 2021-03-02 MILD NONE 1 FALSE
#> AE01-001 HEADACHE 2 2021-03-10 2021-03-12 SEVERE PROBABLE 1 FALSE
#> AE01-002 DIARRHOEA 1 2021-04-01 NA SEVERE PROBABLE 2 TRUE
#> AE01-002 NAUSEA 1 2021-02-01 2021-02-06 MODERATE POSSIBLE 2 FALSE
#> AE01-003 DIZZINESS 1 NA 2021-06-05 MODERATE POSSIBLE 1 FALSE
#> AE01-003 FATIGUE 1 2021-05-01 2021-05-25 SEVERE PROBABLE 3 FALSE
# 3. Population flags ----------------------------------------------------
adsl <- utils::read.csv(ex("adsl_example.csv"))
rules <- utils::read.csv(ex("pop_rules.csv"))
derive_pop_flags(adsl, rules)$SAFFL
#> [1] "Y" "Y" "Y" "Y" "N" "Y" "N" "Y"Read this before grading anything you will report.
grade_lab() grades with the tables admiral ships as package data — atoxgr_criteria_ctcv5 (default), atoxgr_criteria_ctcv4, atoxgr_criteria_ctcv5_uscv, atoxgr_criteria_daids — by calling admiral::derive_var_atoxgr_dir(). This package does not implement any published toxicity standard itself.
"ctcv5" covers 40 terms across 3 SOCs (Blood and lymphatic system disorders, Investigations, Metabolism and nutrition disorders). Non-laboratory CTCAE terms — nausea, fatigue, rash and the rest — are not covered and cannot be graded by this package. A term that is not in the table returns NA, never "0".ATOXDSCL / ATOXDSCH must already hold the criteria term for each record; this package does not guess terms from PARAMCD. Merge your own lookup on first, as admiral’s ADLB template does with admiral::derive_vars_merged(). Terms are matched by exact string, so the "daids" table needs DAIDS term names ("ALT, High"), not CTCAE ones.NA, not "0". Use "ctcv5" for SI units and "ctcv5_uscv" for US conventional units.demo_grading_table.csv is a demo. The threshold fixture in inst/extdata is in pharmaverseadam units. It is not NCI-CTCAE and must never be used to grade a study. It exists so the threshold path has a test fixture. Sponsor threshold tables are still fully supported — they simply carry no published standard of their own.> THRESHOLD high, < THRESHOLD low), for both published criteria and sponsor thresholds. Missing results, terms absent from the table, and results whose unit the table does not cover are all NA, never "0". ATOXGR carries low toxicity as a negative grade, the admiral::derive_var_atoxgr() convention. The input row order and variable labels are returned intact — admiral::derive_var_atoxgr_dir() regroups rows by term and drops labels.RETAIN implementations. A missing end date means ongoing and absorbs later records; a missing onset date is kept as its own episode and reported.NA (e.g. AGE >= 65 with a missing age) sets "N" and reports the count.With pharmaverseadam installed:
episodes <- collapse_ae_episodes(pharmaverseadam::adae)
c(records = nrow(pharmaverseadam::adae), episodes = nrow(episodes))
#> records episodes
#> 1191 867
# pharmaverseadam::adlb is built by admiral's ADLB template with CTCAE v4.03,
# so "ctcv4" must reproduce its own ATOXGR exactly.
same <- function(a, b) (is.na(a) & is.na(b)) | (!is.na(a) & !is.na(b) & a == b)
mean(same(grade_lab(pharmaverseadam::adlb, "ctcv4")$ATOXGR,
pharmaverseadam::adlb$ATOXGR))
#> [1] 1Measured agreement with that dataset’s own ATOXGR, over all 83,652 rows (45,077 of which carry a CTCAE term):
grading |
all rows | rows both sides grade |
|---|---|---|
"ctcv4" |
100.00% | 100.00% (n = 42,553) |
"ctcv5" |
92.72% | 97.10% (n = 37,549) |
"ctcv5_uscv" |
74.78% | 95.17% (n = 22,548) |
"daids" |
49.13% | — (n = 0) |
demo_grading_table.csv |
75.00% | 96.56% (n = 25,003) |
"ctcv4" is the like-for-like comparison and it is exact. The "ctcv5" shortfall is the standards genuinely disagreeing: 2,512 Hypophosphatemia and 2,492 Hyperglycemia records are graded by v4.03 and were dropped from v5, and 749 Creatinine increased records changed criterion — 5,753 of the 6,093 disagreements. "ctcv5_uscv" is lower because that dataset reports SI units, and "daids" grades nothing on it because DAIDS uses its own term names. The demo table’s 96.56% is the number 0.0.0.9000 reported as 96.6%; it measures a demo fixture against CTCAE v4.03 and means nothing about correctness.