$npx -y skills add RConsortium/pharma-skills --skill admiral-bdsDerives ADaM Basic Data Structure (BDS) datasets using the {admiral} R package. Initial scope covers ADVS (vital signs) and ADLB (laboratory values). Use when a user needs to create a BDS findings dataset from SDTM domains, derive parameter assignments, baseline values, change fr
| 1 | # admiral-bds |
| 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 BDS-specific. |
| 6 | |
| 7 | Derives CDISC-conformant BDS findings datasets using {admiral}. Outputs |
| 8 | executable, QC-ready R code for ADVS and ADLB with full derivation traceability. |
| 9 | |
| 10 | See [bds-conventions reference](references/bds-conventions.md) for BDS variable |
| 11 | conventions and record structure. See |
| 12 | [`../admiral-adsl/references/admiral-functions.md`](../admiral-adsl/references/admiral-functions.md) |
| 13 | for function selection guidance shared across the admiral family. |
| 14 | |
| 15 | --- |
| 16 | |
| 17 | ## Inputs |
| 18 | |
| 19 | Before generating code, confirm the following are available or explicitly noted |
| 20 | as absent: |
| 21 | |
| 22 | | Input | Required | Notes | |
| 23 | |---|---|---| |
| 24 | | VS or LB | Yes | Source SDTM domain for ADVS or ADLB respectively | |
| 25 | | ADSL | Yes | Provides TRTSDT, TRTEDT, treatment variables, and population flags | |
| 26 | | ADaM BDS spec | Yes | Parameter list, derivation rules, visit windows, baseline definition | |
| 27 | | Study context | Yes | Baseline window, analysis flag definitions, visit map | |
| 28 | |
| 29 | If ADSL is absent, stop and request it. ADSL variables are required before |
| 30 | baseline flagging and analysis flags can be derived. |
| 31 | |
| 32 | --- |
| 33 | |
| 34 | ## Workflow |
| 35 | |
| 36 | Follow these steps in order. Generate code section by section, not as a single block. |
| 37 | |
| 38 | ### Step 1 — Setup and domain loading |
| 39 | |
| 40 | ```r |
| 41 | library(admiral) |
| 42 | library(dplyr) |
| 43 | library(lubridate) |
| 44 | library(pharmaversesdtm) |
| 45 | |
| 46 | # Load source domain — replace with vs/lb per dataset being derived |
| 47 | vs <- pharmaversesdtm::vs |
| 48 | adsl <- <loaded ADSL dataset> |
| 49 | |
| 50 | # Remove DOMAIN to avoid conflicts in derive_vars_merged() calls |
| 51 | vs <- select(vs, -DOMAIN) |
| 52 | ``` |
| 53 | |
| 54 | ### Step 2 — Merge ADSL backbone variables |
| 55 | |
| 56 | Bring required ADSL variables into the source dataset before any derivations. |
| 57 | At minimum: TRTSDT, TRTEDT, population flags used as analysis set criteria. |
| 58 | |
| 59 | ```r |
| 60 | # REVIEW: Confirm which population flags and ADSL variables are required by |
| 61 | # the ADaM spec for this dataset. Add or remove from new_vars accordingly. |
| 62 | advs <- vs |> |
| 63 | derive_vars_merged( |
| 64 | dataset_add = adsl, |
| 65 | by_vars = exprs(STUDYID, USUBJID), |
| 66 | new_vars = exprs(TRTSDT, TRTEDT, TRT01P, TRT01PN, TRT01A, TRT01AN, |
| 67 | SAFFL, ITTFL) |
| 68 | ) |
| 69 | ``` |
| 70 | |
| 71 | ### Step 3 — Parameter assignment |
| 72 | |
| 73 | Map SDTM test codes to ADaM parameters. Use `derive_vars_merged_lookup()` with a |
| 74 | lookup table driven by the ADaM spec. Do **not** use `derive_vars_merged()` here — |
| 75 | it is not a lookup function and will not correctly handle unmatched records. Do not use `case_when()` or |
| 76 | hardcoded `if_else()` chains. |
| 77 | |
| 78 | ```r |
| 79 | # REVIEW: PARAMCD mapping must match the ADaM spec parameter list exactly. |
| 80 | # Confirm VSTESTCD values in VS and align with ADaM PARAMCD conventions. |
| 81 | # Remove parameters not in scope for this study. |
| 82 | param_lookup <- tibble::tribble( |
| 83 | ~VSTESTCD, ~PARAMCD, ~PARAM, ~PARAMN, |
| 84 | "SYSBP", "SYSBP", "Systolic Blood Pressure", 1L, |
| 85 | "DIABP", "DIABP", "Diastolic Blood Pressure", 2L, |
| 86 | "PULSE", "PULSE", "Pulse Rate", 3L, |
| 87 | "WEIGHT", "WEIGHT", "Weight", 4L, |
| 88 | "HEIGHT", "HEIGHT", "Height", 5L, |
| 89 | "TEMP", "TEMP", "Temperature", 6L |
| 90 | ) |
| 91 | |
| 92 | advs <- advs |> |
| 93 | derive_vars_merged_lookup( |
| 94 | dataset_add = param_lookup, |
| 95 | by_vars = exprs(VSTESTCD), |
| 96 | new_vars = exprs(PARAMCD, PARAM, PARAMN) |
| 97 | ) |> |
| 98 | filter(!is.na(PARAMCD)) # drop records for out-of-scope tests |
| 99 | ``` |
| 100 | |
| 101 | For ADLB, map from LBTESTCD. Include units in PARAM text per ADaM spec. |
| 102 | |
| 103 | ### Step 4 — Analysis value (AVAL, AVALC) |
| 104 | |
| 105 | AVAL is the numeric analysis value. AVALC is the character analysis value. |
| 106 | Derive from the SDTM result variables, applying unit conversions if required. |
| 107 | |
| 108 | ```r |
| 109 | advs <- advs |> |
| 110 | mutate( |
| 111 | AVAL = VSSTRESN, # numeric result in standard units |
| 112 | AVALC = VSSTRESC, # character result (for non-numeric or verbatim) |
| 113 | AVALU = VSSTRESU # analysis value units |
| 114 | ) |
| 115 | ``` |
| 116 | |
| 117 | For ADLB, use LBSTRESN and LBSTRESC. If unit standardisation is required |
| 118 | (e.g. converting mg/dL to mmol/L), apply before AVAL assignment a |