diff --git a/.Rbuildignore b/.Rbuildignore index 97b2c89..005c9d7 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -18,3 +18,4 @@ ^README.Rmd$ ^\.devcontainer$ ^data-raw$ +^doc$ diff --git a/.gitignore b/.gitignore index bbd195c..6bde539 100644 --- a/.gitignore +++ b/.gitignore @@ -50,3 +50,5 @@ admiraltemplate*.tgz # Docs docs/ +/doc/ +/Meta/ diff --git a/_pkgdown.yml b/_pkgdown.yml index dd93285..b409e9b 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -68,8 +68,8 @@ navbar: articles: text: User Guides menu: - - text: Creating ADXX - href: articles/adxx.html + - text: Creating a Metabolic ADVS + href: articles/advs.html history: icon: fa-history href: articles/website-versions.html diff --git a/inst/WORDLIST b/inst/WORDLIST index ceb0c87..d583e2b 100644 --- a/inst/WORDLIST +++ b/inst/WORDLIST @@ -1,13 +1,20 @@ +ADSL +ADVS ADXX ADaM +ADaMs admiralci Arancibia +BDS Biologics +BMI CDISC Changelog DM Farrugia GSK +HIPCIR +WSTCIR LinkedIn Onboarding README @@ -28,4 +35,4 @@ pharmaverse renv repo roxygen - +advs diff --git a/inst/templates/ad_adxx.R b/inst/templates/ad_adxx.R deleted file mode 100644 index 974fd20..0000000 --- a/inst/templates/ad_adxx.R +++ /dev/null @@ -1,20 +0,0 @@ -# Name: ADXX -# -# Label: XXX -# -# Input: xx, xx, xx - -library(admiral) -library(pharmaversesdtm) # Contains example datasets from the CDISC pilot project - -# Add your template ADaM script code - -# Save output ---- - -# Change to whichever directory you want to save the dataset in -dir <- tools::R_user_dir("admiralmetabolic_templates_data", which = "cache") -if (!file.exists(dir)) { - # Create the folder - dir.create(dir, recursive = TRUE, showWarnings = FALSE) -} -# save(adxx, file = file.path(dir, "adxx.rda"), compress = "bzip2") diff --git a/staged_dependencies.yml b/staged_dependencies.yaml similarity index 100% rename from staged_dependencies.yml rename to staged_dependencies.yaml diff --git a/vignettes/advs.Rmd b/vignettes/advs.Rmd new file mode 100644 index 0000000..001a5c3 --- /dev/null +++ b/vignettes/advs.Rmd @@ -0,0 +1,374 @@ +--- +title: "Creating a Metabolic ADVS ADaM" +output: + rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{Creating a Metabolic ADVS ADaM} + %\VignetteEncoding{UTF-8} + %\VignetteEngine{knitr::rmarkdown} +editor_options: + markdown: + wrap: 72 +--- + +```{r setup, include = FALSE} +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>" +) + +library(admiraldev) +``` + +# Introduction + +This article describes creating a vital signs ADaM for metabolic +clinical trials. + +We advise you first consult the `{admiral}` [Creating a BDS Finding ADaM +vignette](https://pharmaverse.github.io/admiral/articles/bds_finding.html). +The programming workflow around creating the general set-up of an `ADVS` +using `{admiral}` functions is the same. In this vignette, we focus on the most common +endpoints and their derivations mainly found in metabolic trials to +avoid repeating information and maintaining the same content in two +places. As such, the code in this vignette is not completely executable; we recommend consulting the ADVS template script to view the full workflow. + +## Required Packages + +The examples of this vignette require the following packages. + +```{r, warning=FALSE, message=FALSE} +library(admiral) +library(admiralmetabolic) +library(pharmaversesdtm) +library(dplyr) +``` + +# Programming Workflow + +- [Read in Data](#readdata) +- [Assign `PARAMCD`, `PARAM`, `PARAMN`, `PARCAT1`](#paramcd) +- [Derive Additional Parameters (e.g. `BMI` for `ADVS`)](#derive_param) +- [Common Metabolic Endpoints](#common_endpoints) + - [Derive Categorization Variables (`AVALCATx`, `BASECATx`)](#cat) + - [Derive Criterion Variables (`CRITy`, `CRITyFL`, `CRITyFLN`)](#crit_vars) +- [Remaining ADVS Set-up](#advs_end) + +## Read in Data {#readdata} + +To start, all data frames needed for the creation of `ADVS` should be +loaded into the global environment. Reading data will usually be a company specific process, however, for the purpose of this vignette, we will use example data from `{pharmaversesdtm}` and `{admiral}`. We will utilize `DM`, `VS` and `ADSL` for the basis of `ADVS`. + +```{r, message=FALSE, warning=FALSE} +dm_metabolic <- admiralmetabolic::dm_metabolic +vs_metabolic <- admiralmetabolic::vs_metabolic +admiral_adsl <- admiral::admiral_adsl + +dm <- convert_blanks_to_na(dm_metabolic) +vs <- convert_blanks_to_na(vs_metabolic) +admiral_adsl <- convert_blanks_to_na(admiral_adsl) +``` + +Within this vignette, `DM` is used as the basis for `ADSL`: + +```{r eval=TRUE} +# Retrieve required variables from admiral ADSL for this vignette that are not present in DM dataset +adsl <- dm %>% + select(-DOMAIN) %>% + mutate(TRT01P = ARM, TRT01A = ACTARM) %>% + left_join(admiral_adsl %>% select(USUBJID, TRTSDT, TRTEDT), by = "USUBJID") +``` + +The following steps are to merge `ADSL` variables with the source data and +derive the usual `ADVS` analysis variables. Note that only the sections required for this vignette are covered in the following steps. To get a detailed guidance on all the steps, refer the `{admiral}` [Creating a BDS Finding ADaM vignette](https://pharmaverse.github.io/admiral/articles/bds_finding.html). + +```{r, eval=TRUE, include=FALSE} +adsl_vars <- exprs(TRTSDT, TRTEDT, TRT01P, TRT01A) + +advs <- derive_vars_merged( + vs, + dataset_add = adsl, + new_vars = adsl_vars, + by_vars = exprs(STUDYID, USUBJID) +) + +advs <- derive_vars_dt(advs, new_vars_prefix = "A", dtc = VSDTC) + +advs <- + derive_vars_dy(advs, reference_date = TRTSDT, source_vars = exprs(ADT)) +``` + +## Assign `PARAMCD`, `PARAM`, `PARAMN`, `PARCAT1` {#paramcd} + +The next step is to assign parameter level values such as `PARAMCD`, `PARAM`, +`PARAMN`, `PARCAT1`, etc. For this, a lookup can be created based on +the SDTM `--TESTCD` value to join to the source data. +One key addition in metabolic trials are vital sign parameters associated to body measurements, such as `BMI`, `HIPCIR`, and `WSTCIR`. + +```{r, echo=TRUE, message=FALSE} +param_lookup <- tribble( + ~VSTESTCD, ~PARAMCD, ~PARAM, ~PARAMN, ~PARCAT1, ~PARCAT1N, + "HEIGHT", "HEIGHT", "Height (cm)", 1, "Subject Characteristic", 1, + "WEIGHT", "WEIGHT", "Weight (kg)", 2, "Subject Characteristic", 1, + "BMI", "BMI", "Body Mass Index(kg/m^2)", 3, "Subject Characteristic", 1, + "HIPCIR", "HIPCIR", "Hip Circumference (cm)", 4, "Subject Characteristic", 1, + "WSTCIR", "WSTCIR", "Waist Circumference (cm)", 5, "Subject Characteristic", 1, + "DIABP", "DIABP", "Diastolic Blood Pressure (mmHg)", 6, "Vital Sign", 2, + "PULSE", "PULSE", "Pulse Rate (beats/min)", 7, "Vital Sign", 2, + "SYSBP", "SYSBP", "Systolic Blood Pressure (mmHg)", 8, "Vital Sign", 2, + "TEMP", "TEMP", "Temperature (C)", 9, "Vital Sign", 2 +) +``` + +This lookup may now be joined to the source data and this is how the +parameters will look like: + +```{r, eval=TRUE, include=TRUE, message=FALSE} +advs <- derive_vars_merged_lookup( + advs, + dataset_add = param_lookup, + new_vars = exprs(PARAMCD, PARAM, PARAMN, PARCAT1, PARCAT1N), + by_vars = exprs(VSTESTCD) +) +``` + +```{r, eval=TRUE, echo=FALSE} +advs_param <- distinct(advs, USUBJID, PARAMCD, VSTESTCD, PARAM, PARCAT1, PARCAT1N) + +dataset_vignette(advs_param, display_vars = exprs(USUBJID, VSTESTCD, PARAMCD, PARAM, PARCAT1, PARCAT1N)) +``` + + +```{r, eval=TRUE, include=FALSE} +advs <- mutate( + advs, + AVAL = VSSTRESN +) +``` + +## Derive Additional Parameters (e.g. `BMI` for `ADVS`) {#derive_param} + +In metabolic trials, `BMI` is often calculated at source. But while creating the `ADVS` +dataset, we re-derive `BMI` from the collected height and weight values. +This is done to ensure that the `BMI` is calculated consistently across +all subjects and visits. + +In this step, we create parameter Body Mass Index (`BMI`) for the `ADVS` +domain using the `derive_param_bmi()` function. Note that only variables +specified in the `by_vars` argument will be populated in the newly +created records. Also note that if height is collected only once for a +subject use `constant_by_vars` to specify the function to merge by the +subject-level variable - otherwise BMI is only calculated for visits +where both are collected. + +```{r eval=TRUE} +# Removing BMI collected at source from the dataset +advs <- advs %>% filter(!VSTESTCD == "BMI") + +advs <- derive_param_bmi( + advs, + by_vars = c( + get_admiral_option("subject_keys"), + exprs(!!!adsl_vars, VISIT, VISITNUM, ADT, ADY, VSTPT, VSTPTNUM) + ), + set_values_to = exprs( + PARAMCD = "BMI", + PARAM = "Body Mass Index (kg/m^2)", + PARAMN = 3, + PARCAT1 = "Subject Characteristic", + PARCAT1N = 1 + ), + get_unit_expr = VSSTRESU, + filter = VSSTAT != "NOT DONE" | is.na(VSSTAT), + constant_by_vars = exprs(USUBJID) +) +``` + +```{r, eval=TRUE, echo=FALSE} +dataset_vignette( + arrange(advs, USUBJID, VISITNUM, VSTPTNUM, ADT, PARAMCD), + display_vars = exprs(USUBJID, VSTESTCD, PARAMCD, PARAM, VISIT, AVAL), + filter = PARAMCD %in% c("BMI") +) +``` + +```{r eval=TRUE, include=FALSE} +advs <- restrict_derivation( + advs, + derivation = derive_var_extreme_flag, + args = params( + by_vars = c(get_admiral_option("subject_keys"), exprs(PARAMCD)), + order = exprs(ADT, VSTPTNUM, VISITNUM), + new_var = ABLFL, + mode = "last" + ), + filter = (!is.na(AVAL) & ADT <= TRTSDT) +) + +advs <- derive_var_base( + advs, + by_vars = c(get_admiral_option("subject_keys"), exprs(PARAMCD)), + source_var = AVAL, + new_var = BASE +) + +advs <- derive_var_chg(advs) + +advs <- derive_var_pchg(advs) +``` + +## Common Metabolic Endpoints {#common_endpoints} + +In the following sections, we will explore some of the most common +endpoints typically observed in metabolic trials. + +One such endpoint is the improvement in weight category from baseline to +the end of treatment, which is often assessed using Body Mass Index +(`BMI`). To capture this, we will derive variables such as `AVALCATy` +and `BASECATy`, as detailed in the subsequent section. + +Additionally, the achievement of weight reduction thresholds, such as ≥ +5%, ≥ 10%, or ≥ 15% from baseline to end of treatment or at a certain visit, +is a common endpoint in metabolic trials. To accommodate these criteria, +we will derive relevant criterion variables such as `CRITy`, `CRITyFL`, +and `CRITyFLN`, with the necessary functions provided by `{admiral}` +outlined below. + +### Derive Categorization Variables (`AVALCATx`, `BASECATx`) {#cat} + +`{admiral}` does not currently have a generic function to aid in +assigning `AVALCATy`/ `AVALCAvN` and `BASECATy`/ `BASECAvN` values. +Below is a simple example of how these values may be assigned: + +```{r eval=TRUE} +avalcat_lookup <- tibble::tribble( + ~PARAMCD, ~AVALCA1N, ~AVALCAT1, + "BMI", 1, "Underweight", + "BMI", 2, "Normal weight", + "BMI", 3, "Overweight", + "BMI", 4, "Obesity class I", + "BMI", 5, "Obesity class II", + "BMI", 6, "Obesity class III", + "BMI", NA, NA_character_ +) + +format_avalcat1n <- function(param, aval) { + case_when( + param == "BMI" & aval < 18.5 ~ 1, + param == "BMI" & aval >= 18.5 & aval < 25 ~ 2, + param == "BMI" & aval >= 25 & aval < 30 ~ 3, + param == "BMI" & aval >= 30 & aval < 35 ~ 4, + param == "BMI" & aval >= 35 & aval < 40 ~ 5, + param == "BMI" & aval >= 40 ~ 6, + TRUE ~ NA_real_ + ) +} + +advs <- advs %>% + mutate(AVALCA1N = format_avalcat1n(param = PARAMCD, aval = AVAL)) %>% + derive_vars_merged( + avalcat_lookup, + by = exprs(PARAMCD, AVALCA1N) + ) +``` + +```{r eval=TRUE, echo=FALSE} +dataset_vignette( + advs, + display_vars = exprs(USUBJID, PARAMCD, VISIT, AVAL, AVALCA1N, AVALCAT1), + filter = PARAMCD == "BMI" +) +``` + +In a similar way, we will create `BASECATy`/ `BASECAvN` variables. + +```{r eval=TRUE} +basecat_lookup <- tibble::tribble( + ~PARAMCD, ~BASECA1N, ~BASECAT1, + "BMI", 1, "Underweight", + "BMI", 2, "Normal weight", + "BMI", 3, "Overweight", + "BMI", 4, "Obesity class I", + "BMI", 5, "Obesity class II", + "BMI", 6, "Obesity class III", + "BMI", NA, NA_character_ +) + +format_basecat1n <- function(param, base) { + case_when( + param == "BMI" & base < 18.5 ~ 1, + param == "BMI" & base >= 18.5 & base < 25 ~ 2, + param == "BMI" & base >= 25 & base < 30 ~ 3, + param == "BMI" & base >= 30 & base < 35 ~ 4, + param == "BMI" & base >= 35 & base < 40 ~ 5, + param == "BMI" & base >= 40 ~ 6, + TRUE ~ NA_real_ + ) +} +advs <- advs %>% + mutate(BASECA1N = format_basecat1n(param = PARAMCD, base = BASE)) %>% + derive_vars_merged( + basecat_lookup, + by = exprs(PARAMCD, BASECA1N) + ) +``` + +```{r, eval=TRUE, echo=FALSE} +dataset_vignette( + advs, + display_vars = exprs(USUBJID, PARAMCD, VISIT, AVAL, BASE, ABLFL, BASECA1N, BASECAT1), + filter = PARAMCD == "BMI" +) +``` + +### Derive Criterion Variables (`CRITy`, `CRITyFL`, `CRITyFLN`) {#crit_vars} + +For deriving criterion variables (`CRITy`, `CRITyFL`, `CRITyFLN`) +`{admiral}` provides +[`derive_vars_crit_flag()`](https://pharmaverse.github.io/admiral/dev/reference/derive_vars_crit_flag.html). +It ensures that they are derived in an ADaM-compliant way (see +documentation of the function for details). + +In most cases the criterion depends on the parameter. In the following +example, the criterion flags for weight based on percentage change in +weight reduction from baseline is derived. Additional criterion flags +can be added as needed. + +```{r eval=TRUE} +advs <- advs %>% + derive_vars_crit_flag( + condition = PCHG <= -5 & PARAMCD == "WEIGHT", + description = "Achievement of ≥ 5% weight reduction from baseline", + crit_nr = 1, + values_yn = TRUE, + create_numeric_flag = FALSE + ) %>% + derive_vars_crit_flag( + condition = PCHG <= -10 & PARAMCD == "WEIGHT", + description = "Achievement of ≥ 10% weight reduction from baseline", + crit_nr = 2, + values_yn = TRUE, + create_numeric_flag = FALSE + ) +``` + +```{r, eval=TRUE, echo=FALSE} +dataset_vignette( + arrange(advs, USUBJID, VISITNUM, VSTPTNUM, PARAMCD), + display_vars = exprs(USUBJID, PARAMCD, PCHG, CRIT1, CRIT1FL, CRIT2, CRIT2FL), + filter = PARAMCD %in% c("WEIGHT") +) +``` + +## Remaining ADVS Set-up {#advs_end} + +The `{admiral}` [Creating a BDS Finding ADaM +vignette](https://pharmaverse.github.io/admiral/articles/bds_finding.html) +covers all the steps that are not shown here, such as merging the +parameter-level values, timing variables, and analysis flags. + +# Example Scripts {#example} + +ADaM | Sample Code +---- | -------------- +ADVS | [ad_advs.R](https://github.com/pharmaverse/admiralmetabolic/blob/main/inst/templates/ad_advs.R){target="_blank"} diff --git a/vignettes/adxx.Rmd b/vignettes/adxx.Rmd deleted file mode 100644 index b847846..0000000 --- a/vignettes/adxx.Rmd +++ /dev/null @@ -1,30 +0,0 @@ ---- -title: "Creating ADXX" -output: - rmarkdown::html_vignette -vignette: > - %\VignetteIndexEntry{Creating ADXX} - %\VignetteEngine{knitr::rmarkdown} - %\VignetteEncoding{UTF-8} ---- - -```{r setup, include = FALSE} -knitr::opts_chunk$set( - collapse = TRUE, - comment = "#>" -) -``` - -# Introduction - -This article describes creating an `ADXX` ADaM. - -# Programming Workflow - -Steps involved to create an `ADXX` ADaM. - -# Example Scripts - -ADaM | Sourcing Command ----- | -------------- -ADXX | `admiral::use_ad_template("ADXX", package = "admiraltemplate")`