Skip to contents

Overview

Each endpoint needs to be generated from a single analysis data set containing information from one or more ADaM data sets. Each analysis data set is created by a custom ADaM function written by the trial programmer that is referenced in the endpoint specification via the data_prepare parameter. The ADaM function contains instructions to what ADaM data sets to join, how to join, and what custom variables e.g., new groupings, to create (if any).

There are three requirements for the ADaM function:

  1. It must have exactly one input argument study_metadata which is an endpoint specification parameter, preferably a 1-element list, that contains any relevant information about the study that may be used to read the ADaM data sets. If no such information is needed, then leave study_metadata unused in the function and set it as an empty list() in the endpoint specification.
  2. It must each return a data.table object. If you do not work in data.table, you can do this by converting your tibble or data.frame object to a data.table object at the end of the function via data.table::as.data.table(my_data_frame).
  3. The returned table must contain all the ADAM variables (and derived variables) that are mentioned in the endpoint specification and also the subject ID variable USUBJID.

In summary, the analysis data set generation is controlled with the following two parameters in the endpoint specification:

  • data_prepare: Reference to a custom function that returns a single consolidated analysis table that contains all ADaM data needed in the endpoint.
  • study_metadata: Object containing study specifics that are relevant for reading the ADAM data. Must be parsed as the input to the ADaM and ADSL functions. May be empty if not needed.

Examples

Ex 1.1

Here is an example of an ADAM function that first reads the ADSL data table from {pharmaverseadam}, filters it down to two treatment arms, and enriches it with a derived variable. Then it merges the enriched ADSL with ADAE from {pharmaverseadam} and return a single table with all the ADaM information from ADSL and ADAE:

# Example of ADaM function that merges information from ADSL and ADAE
mk_adam_ex1_1 <- function(study_metadata) {

  # Read ADSL from {pharmaverseadam} 
  adsl <- data.table::as.data.table(pharmaverseadam::adsl)
  
  # Filter treatment arms
  adsl <- adsl[adsl$TRT01A %in% c('Placebo', 'Xanomeline High Dose')]
  
  # New derived ADSL variable 
  adsl[, AGEGR2 := data.table::fcase(AGE < 70, "AGE < 70",
                                     AGE >= 70, "AGE >= 70")]
  
  # Read ADAE from {pharmaverseadam}
  adae <- data.table::as.data.table(pharmaverseadam::adae)
  
  # Merge ADSL and ADAE
  adae_out <-
    merge(adsl, adae[, c(setdiff(names(adae), names(adsl)), "USUBJID"), with =
                       F], by = "USUBJID", all = TRUE)
  return(adae_out)
}
Ex 1.2

You might also have cases where information from several ADAM tables are required in your endpoint. Here is an example that returns the same ADaM information as the example above with the addition of the baseline body weight extracted from ADVS. So information from three ADaM tables are merged and returned in a single analysis data set:

# Example of ADaM function that merges information from three ADaM tables
mk_adam_ex1_2 <- function(study_metadata) {
  
  # Read ADSL from {pharmaverseadam} 
  adsl <- data.table::as.data.table(pharmaverseadam::adsl)
  
  # Filter treatment arms
  adsl <- adsl[adsl$TRT01A %in% c('Placebo', 'Xanomeline High Dose')]
  
  # New derived ADSL variable 
  adsl[, AGEGR2 := data.table::fcase(AGE < 70, "AGE < 70",
                                     AGE >= 70, "AGE >= 70")]
  
  # Read ADAE from {pharmaverseadam}
  adae <- data.table::as.data.table(pharmaverseadam::adae)

  # Read ADVS from {pharmaverseadam}
  advs <- data.table::as.data.table(pharmaverseadam::advs)
  
  # Identify baseline body weight
  advs_bw <- advs[advs$PARAMCD == "WEIGHT" & advs$VISIT == "BASELINE"]
  
  # Create new variable bw_baseline
  advs_bw[["bw_baseline"]] <- advs_bw[["AVAL"]]
  
  # Merge ADSL, ADAE and baseline body weight from ADVS
  ax_out <-
    merge(adsl, adae[, c(setdiff(names(adae), names(adsl)), "USUBJID"), with = F], 
          by = "USUBJID", all.x = TRUE) |> 
    merge(x=_, advs_bw[, c("bw_baseline", "USUBJID")], by = "USUBJID", all.x = TRUE)
  
  return(ax_out)
}
Ex 1.3

The ADaM functions, once defined, need to be linked to the corresponding endpoint specifications via the data_prepare parameter. The creation of each endpoint specification is facilitated by the mk_endpoint_str function wherein this data_prepare parameter is established. In the following example, the mk_adam_ex1_2 function is utilized to produce the analysis data intended for an endpoint.

# Example of endpoint specification of ADaM function.
# The dots must be replaced with other required parameters.
ep_spec_ex1_3  <- chef::mk_endpoint_str(
  data_prepare = mk_adam_ex1_2,
  ...)