$npx -y skills add RConsortium/pharma-skills --skill admiral-adslDerives an ADaM Subject-Level Analysis Dataset (ADSL) using the {admiral} R package and pharmaverse ecosystem. Use when a user needs to create ADSL from SDTM domains, derive standard subject-level variables (treatment dates, disposition, demographics, population flags), or genera
| 1 | # admiral-adsl |
| 2 | |
| 3 | > Shared conventions (library setup, pipe style, date rules, flag convention, |
| 4 | > `# REVIEW:` annotations, `stopifnot()` patterns) are defined in the parent |
| 5 | > [`../SKILL.md`](../SKILL.md). The workflow below is ADSL-specific. |
| 6 | |
| 7 | Derives a CDISC-conformant ADSL dataset using {admiral}. Outputs executable, |
| 8 | QC-ready R code with derivation logic traceable to the ADaM specification. |
| 9 | |
| 10 | See [admiral-functions reference](references/admiral-functions.md) for function |
| 11 | selection guidance. See [adsl-conventions reference](references/adsl-conventions.md) |
| 12 | for CDISC variable conventions. |
| 13 | |
| 14 | --- |
| 15 | |
| 16 | ## Inputs |
| 17 | |
| 18 | Before generating code, confirm the following are available or explicitly noted |
| 19 | as absent: |
| 20 | |
| 21 | | Input | Required | Notes | |
| 22 | |---|---|---| |
| 23 | | DM | Yes | Subject spine; one record per USUBJID | |
| 24 | | EX | Yes | Exposure; needed for treatment dates and SAFFL | |
| 25 | | DS | Yes | Disposition; needed for EOSSTT, DCSREAS | |
| 26 | | DV | No | Protocol deviations; needed for PPROTFL | |
| 27 | | MH | No | Medical history flags if protocol requires | |
| 28 | | VS | No | HEIGHTBL, WEIGHTBL, BMIBL if in scope | |
| 29 | | ADaM ADSL spec | Yes | Variable list, derivation rules, grouping cut-points | |
| 30 | | Study context | Yes | Treatment arm names, population flag definitions | |
| 31 | |
| 32 | If required domains are absent, stop and request them. If optional domains are |
| 33 | absent, omit the corresponding derivations and note this in code comments. |
| 34 | |
| 35 | --- |
| 36 | |
| 37 | ## Workflow |
| 38 | |
| 39 | Follow these steps in order. Generate code section by section, not as a single |
| 40 | block. |
| 41 | |
| 42 | ### Step 1 — Setup and domain loading |
| 43 | |
| 44 | ```r |
| 45 | library(admiral) |
| 46 | library(dplyr) |
| 47 | library(lubridate) |
| 48 | library(pharmaversesdtm) |
| 49 | |
| 50 | # Load SDTM domains |
| 51 | dm <- pharmaversesdtm::dm |
| 52 | ex <- pharmaversesdtm::ex |
| 53 | ds <- pharmaversesdtm::ds |
| 54 | # mh <- pharmaversesdtm::mh # uncomment if in scope |
| 55 | |
| 56 | # Confirm one record per USUBJID in DM before proceeding |
| 57 | stopifnot(nrow(dm) == n_distinct(dm$USUBJID)) |
| 58 | ``` |
| 59 | |
| 60 | ### Step 2 — Subject spine |
| 61 | |
| 62 | Start from DM. One record per USUBJID is mandatory at this step and must be |
| 63 | preserved throughout. Select only variables needed downstream. |
| 64 | |
| 65 | ```r |
| 66 | adsl <- dm |> |
| 67 | select( |
| 68 | STUDYID, USUBJID, SUBJID, SITEID, |
| 69 | AGE, AGEU, SEX, RACE, ETHNIC, COUNTRY, |
| 70 | ARM, ARMCD, ACTARM, ACTARMCD, |
| 71 | DMDTC, RFSTDTC, RFENDTC, |
| 72 | DTHFL, DTHDTC |
| 73 | ) |
| 74 | ``` |
| 75 | |
| 76 | ### Step 3 — Treatment dates (TRTSDTM, TRTSTMF, TRTEDTM, TRTETMF, TRTSDT, TRTEDT) |
| 77 | |
| 78 | Derive datetimes first, then extract date-only variables. Always include |
| 79 | `time_imputation` arguments and always retain imputation flags (TRTSTMF, |
| 80 | TRTETMF) in `new_vars` — setting `flag_imputation = "auto"` without capturing |
| 81 | the flag variables provides no traceability benefit. |
| 82 | |
| 83 | Remove DOMAIN from EX before merging to avoid variable conflicts. |
| 84 | |
| 85 | ```r |
| 86 | ex_dtm <- ex |> |
| 87 | select(-DOMAIN) |> |
| 88 | derive_vars_dtm( |
| 89 | dtc = EXSTDTC, |
| 90 | new_vars_prefix = "EXST", |
| 91 | date_imputation = "first", |
| 92 | time_imputation = "first", |
| 93 | flag_imputation = "auto" |
| 94 | ) |> |
| 95 | derive_vars_dtm( |
| 96 | dtc = EXENDTC, |
| 97 | new_vars_prefix = "EXEN", |
| 98 | date_imputation = "last", |
| 99 | time_imputation = "last", |
| 100 | flag_imputation = "auto" |
| 101 | ) |
| 102 | |
| 103 | # TRTSDTM / TRTSTMF: first dose datetime and imputation flag |
| 104 | # REVIEW: The placebo filter (EXTRT == "PLACEBO") must be confirmed against the |
| 105 | # protocol. In some studies EXDOSE > 0 is sufficient; in others EXDOSE = 0 |
| 106 | # for placebo and EXTRT must be used. Adjust condition per protocol definition. |
| 107 | adsl <- adsl |> |
| 108 | derive_vars_merged( |
| 109 | dataset_add = ex_dtm, |
| 110 | by_vars = exprs(STUDYID, USUBJID), |
| 111 | new_vars = exprs(TRTSDTM = EXSTDTM, TRTSTMF = EXSTTMF), |
| 112 | order = exprs(EXSTDTM), |
| 113 | mode = "first", |
| 114 | filter_add = (EXDOSE > 0 | EXTRT == "PLACEBO") & !is.na(EXSTDTM) |
| 115 | ) |> |
| 116 | # TRTEDTM / TRTETMF: last dose datetime and imputation flag |
| 117 | # REVIEW: If subjects have non-contiguous EX records, TRTEDTM reflects the |
| 118 | # last administration date only. Flag for QC if exposure gaps exist. |
| 119 | derive_vars_merged( |
| 120 | dataset_add = ex_dtm, |
| 121 | by_vars = exprs(STUDYID, USUBJID), |
| 122 | new_vars = exprs(TRTEDTM = EXENDTM, TRTETMF = EXENTMF), |
| 123 | order = exprs(EXENDTM), |
| 124 | mode = "last", |
| 125 | filter_add = (EXDOSE > 0 | EXTRT == "PLACEBO") & !is.na(EXENDTM) |
| 126 | ) |> |
| 127 | mutate( |
| 128 | TRTSDT = as.Date(TRTSDTM), |
| 129 | TRTEDT = as.Date(TRTEDTM) |
| 130 | ) |
| 131 | ` |