The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.

Creating a Metabolic ADLB ADaM

Introduction

This article describes creating a laboratory ADaM for metabolic clinical trials.

We advise you first consult the {admiral} Creating a BDS Finding ADaM vignette. The programming workflow around creating the general set-up of an ADLB using {admiral} functions is the same. In this vignette, we focus on common ADLB derivations in metabolic studies and avoid repeating information and maintaining the same content in two places.

Note: All examples assume CDISC SDTM and/or ADaM format as input unless otherwise specified.

Required Packages

The examples of this vignette require the following packages.

library(admiral)
library(admiralmetabolic)
library(pharmaversesdtm)
library(dplyr)
library(stringr)

Programming Workflow

Read in Data

To start, all data frames needed for the creation of the ADaM dataset 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 {admiralmetabolic}. We will utilize LB and ADSL data.

lb_metabolic <- pharmaversesdtm::lb_metabolic
admiralmetabolic_adsl <- admiralmetabolic::admiralmetabolic_adsl

lb <- convert_blanks_to_na(lb_metabolic)
adsl <- convert_blanks_to_na(admiralmetabolic_adsl)

Define Lookup Tables

Define parameter lookup table used to derive PARAMCD, PARAM, and PARAMN variables.

# Assign PARAMCD, PARAM, and PARAMN
param_lookup <- tibble::tribble(
  ~LBTESTCD, ~PARAMCD, ~PARAM, ~PARAMN,
  "ALB", "ALB", "Albumin (g/L)", 1,
  "ALP", "ALKPH", "Alkaline Phosphatase (U/L)", 2,
  "AST", "AST", "Aspartate Aminotransferase (U/L)", 3,
  "CHOL", "CHOLES", "Cholesterol (mmol/L)", 4,
  "GGT", "GGT", "Gamma Glutamyl Transferase (U/L)", 5,
  "GLUC", "GLUC", "Glucose (mmol/L)", 6,
  "HBA1CHGB", "HBA1CHGB", "Hemoglobin A1C/Hemoglobin (mmol/mol)", 7,
  "INSULIN", "INSULIN", "Insulin (mIU/L)", 8,
  "TRIG", "TRIG", "Triglycerides (mg/dL)", 9
)

Derive Core ADLB Variables

The basic parameters and timing variables can be derived similarly to other BDS finding ADaMs. For the derivation of Glucose and Insulin, only fasted results (where LBFAST = "Y") are considered. For all other laboratory tests, the fasting status does not affect their inclusion in the dataset at this stage.

# Define required ADSL variables for derivations
adsl_vars <- exprs(TRTSDT, TRTEDT, TRT01A, TRT01P)

adlb <- lb %>%
  # Remove non-fasted GLUC and INSULIN results
  filter(!(LBTESTCD %in% c("GLUC", "INSULIN") & LBFAST != "Y")) %>%
  # Join ADSL with LB (need TRTSDT for ADY derivation)
  derive_vars_merged(
    dataset_add = adsl,
    new_vars = adsl_vars,
    by_vars = get_admiral_option("subject_keys")
  ) %>%
  # Calculate ADT, ADY
  derive_vars_dt(
    new_vars_prefix = "A",
    dtc = LBDTC
  ) %>%
  derive_vars_dy(reference_date = TRTSDT, source_vars = exprs(ADT))

adlb <- adlb %>%
  # Add PARAMCD PARAM and PARAMN - from parameter lookup table
  derive_vars_merged_lookup(
    dataset_add = param_lookup,
    new_vars = exprs(PARAMCD, PARAM, PARAMN),
    by_vars = exprs(LBTESTCD)
  ) %>%
  ## Calculate PARCAT1 PARCAT2 AVAL AVALC ANRLO ANRHI
  slice_derivation(
    derivation = mutate,
    args = params(
      PARCAT1 = LBCAT,
    ),
    # Handle specific parameters requiring conventional units (CV)
    derivation_slice(
      filter = LBTESTCD %in% c("TRIG", "INSULIN"),
      args = params(
        PARCAT2 = "CV",
        AVAL = as.numeric(LBORRES),
        AVALC = NA_character_,
        ANRLO = as.numeric(LBORNRLO),
        ANRHI = as.numeric(LBORNRHI)
      )
    ),
    # Handle other parameters using standard units (SI)
    derivation_slice(
      filter = TRUE,
      args = params(
        PARCAT2 = "SI",
        AVAL = LBSTRESN,
        # Only populate AVALC if character value is non-redundant with AVAL
        AVALC = if_else(
          is.na(AVAL) | as.character(AVAL) != LBSTRESC,
          LBSTRESC,
          NA_character_
        ),
        ANRLO = LBSTNRLO,
        ANRHI = LBSTNRHI
      )
    )
  )
#> All `LBTESTCD` are mapped.
STUDYID USUBJID ADT ADY PARAMCD PARAM PARAMN PARCAT1 PARCAT2 AVAL AVALC ANRLO ANRHI
CDISCPILOT01 01-701-1015 2013-12-26 -7 ALB Albumin (g/L) 1 CHEMISTRY SI 38.00000 NA 33.00000 49.00000
CDISCPILOT01 01-701-1015 2013-12-26 -7 ALKPH Alkaline Phosphatase (U/L) 2 CHEMISTRY SI 34.00000 NA 35.00000 115.00000
CDISCPILOT01 01-701-1015 2013-12-26 -7 AST Aspartate Aminotransferase (U/L) 3 CHEMISTRY SI 40.00000 NA 9.00000 34.00000
CDISCPILOT01 01-701-1015 2013-12-26 -7 CHOLES Cholesterol (mmol/L) 4 CHEMISTRY SI 5.94780 NA 4.03000 7.76000
CDISCPILOT01 01-701-1015 2013-12-26 -7 GGT Gamma Glutamyl Transferase (U/L) 5 CHEMISTRY SI 15.00000 NA 5.00000 50.00000
CDISCPILOT01 01-701-1015 2013-12-26 -7 GLUC Glucose (mmol/L) 6 CHEMISTRY SI 4.71835 NA 2.80000 13.90000
CDISCPILOT01 01-701-1015 2013-12-26 -7 HBA1CHGB Hemoglobin A1C/Hemoglobin (mmol/mol) 7 CHEMISTRY SI 62.84175 NA 20.21865 38.79795
CDISCPILOT01 01-701-1015 2013-12-26 -7 INSULIN Insulin (mIU/L) 8 CHEMISTRY CV 14.40000 NA 2.00000 25.00000
CDISCPILOT01 01-701-1015 2013-12-26 -7 TRIG Triglycerides (mg/dL) 9 CHEMISTRY CV 111.10000 NA 0.00000 150.00000
CDISCPILOT01 01-701-1015 2014-01-16 15 ALB Albumin (g/L) 1 CHEMISTRY SI 39.00000 NA 33.00000 49.00000

Derive Visit Information

Derive Analysis Visit (AVISIT) and Analysis Visit Number (AVISITN).

adlb <- adlb %>%
  mutate(
    AVISIT = case_when(
      str_detect(VISIT, "SCREEN") ~ "Baseline",
      !is.na(VISIT) ~ str_to_title(VISIT),
      TRUE ~ NA_character_
    ),
    AVISITN = case_when(
      AVISIT == "Baseline" ~ 0,
      str_detect(VISIT, "WEEK") ~ as.integer(str_extract(VISIT, "\\d+")),
      TRUE ~ NA_integer_
    )
  )
STUDYID USUBJID PARAMCD PARAM PARCAT1 AVAL ADY AVISIT AVISITN
CDISCPILOT01 01-701-1015 ALB Albumin (g/L) CHEMISTRY 38.00000 -7 Baseline 0
CDISCPILOT01 01-701-1015 ALKPH Alkaline Phosphatase (U/L) CHEMISTRY 34.00000 -7 Baseline 0
CDISCPILOT01 01-701-1015 AST Aspartate Aminotransferase (U/L) CHEMISTRY 40.00000 -7 Baseline 0
CDISCPILOT01 01-701-1015 CHOLES Cholesterol (mmol/L) CHEMISTRY 5.94780 -7 Baseline 0
CDISCPILOT01 01-701-1015 GGT Gamma Glutamyl Transferase (U/L) CHEMISTRY 15.00000 -7 Baseline 0
CDISCPILOT01 01-701-1015 GLUC Glucose (mmol/L) CHEMISTRY 4.71835 -7 Baseline 0
CDISCPILOT01 01-701-1015 HBA1CHGB Hemoglobin A1C/Hemoglobin (mmol/mol) CHEMISTRY 62.84175 -7 Baseline 0
CDISCPILOT01 01-701-1015 INSULIN Insulin (mIU/L) CHEMISTRY 14.40000 -7 Baseline 0
CDISCPILOT01 01-701-1015 TRIG Triglycerides (mg/dL) CHEMISTRY 111.10000 -7 Baseline 0
CDISCPILOT01 01-701-1015 ALB Albumin (g/L) CHEMISTRY 39.00000 15 Week 2 2

For deriving visits based on time-windows, see {admiral} Visit and Period Variables.

Derive Metabolic Parameters

In addition to the core ADLB variables, several metabolic parameters and scores will be derived based on laboratory data and vital signs. These derivations include:

To derive these parameters and scores, the following variables will be needed:

Add variables required for derivation

In this section, we will merge relevant variables needed to derive metabolic parameter from the ADVS (Analysis Dataset for Vital Signs) dataset into the ADLB dataset. This is necessary to include variables such as BMI and Waist Circumference, which are required for the derivation of FLI score parameter in subsequent section.

# Load ADVS dataset (assuming it has been created by ad_advs.R)
admiralmetabolic_advs <- admiralmetabolic::admiralmetabolic_advs
advs <- convert_blanks_to_na(admiralmetabolic_advs)

# Merge BMI and WSTCIR from ADVS to ADLB based on subject and date
adlb <- adlb %>%
  derive_vars_transposed(
    advs,
    by_vars = exprs(!!!get_admiral_option("subject_keys"), ADT),
    key_var = PARAMCD,
    value_var = AVAL,
    filter = PARAMCD %in% c("BMI", "WSTCIR")
  )

Please note that in this example we merge on ADT, but it is also possible to merge on AVISIT or other windowing algorithms specified in the statistical analysis plan.

STUDYID USUBJID PARAMCD PARAM AVAL ADT ADY AVISIT AVISITN BMI WSTCIR
CDISCPILOT01 01-701-1015 ALB Albumin (g/L) 38.00000 2013-12-26 -7 Baseline 0 38.10500 99
CDISCPILOT01 01-701-1015 ALKPH Alkaline Phosphatase (U/L) 34.00000 2013-12-26 -7 Baseline 0 38.10500 99
CDISCPILOT01 01-701-1015 AST Aspartate Aminotransferase (U/L) 40.00000 2013-12-26 -7 Baseline 0 38.10500 99
CDISCPILOT01 01-701-1015 CHOLES Cholesterol (mmol/L) 5.94780 2013-12-26 -7 Baseline 0 38.10500 99
CDISCPILOT01 01-701-1015 GGT Gamma Glutamyl Transferase (U/L) 15.00000 2013-12-26 -7 Baseline 0 38.10500 99
CDISCPILOT01 01-701-1015 GLUC Glucose (mmol/L) 4.71835 2013-12-26 -7 Baseline 0 38.10500 99
CDISCPILOT01 01-701-1015 HBA1CHGB Hemoglobin A1C/Hemoglobin (mmol/mol) 62.84175 2013-12-26 -7 Baseline 0 38.10500 99
CDISCPILOT01 01-701-1015 INSULIN Insulin (mIU/L) 14.40000 2013-12-26 -7 Baseline 0 38.10500 99
CDISCPILOT01 01-701-1015 TRIG Triglycerides (mg/dL) 111.10000 2013-12-26 -7 Baseline 0 38.10500 99
CDISCPILOT01 01-701-1015 ALB Albumin (g/L) 39.00000 2014-01-16 15 Week 2 2 38.53219 100

Derive HOMA-IR index

This part describes how to calculate the Homeostasis Model Assessment – Insulin Resistance (HOMA-IR) index from fasting plasma glucose and fasting plasma insulin. This derivation does not require merging data from other datasets.

# Derive HOMA-IR using derive_param_computed
adlb <- adlb %>%
  derive_param_computed(
    by_vars = exprs(!!!get_admiral_option("subject_keys"), AVISIT, AVISITN, ADT, ADY, !!!adsl_vars),
    parameters = c("INSULIN", "GLUC"),
    set_values_to = exprs(
      AVAL = AVAL.INSULIN * AVAL.GLUC / 22.5,
      PARAMCD = "HOMAIR",
      PARAM = "Homeostasis Model Assessment - Insulin Resistance",
      PARAMN = 10
    )
  )
STUDYID USUBJID PARAMCD PARAM AVAL ADY AVISIT AVISITN
CDISCPILOT01 01-701-1015 HOMAIR Homeostasis Model Assessment - Insulin Resistance 3.019744 -7 Baseline 0
CDISCPILOT01 01-701-1015 HOMAIR Homeostasis Model Assessment - Insulin Resistance 8.289493 15 Week 2 2
CDISCPILOT01 01-701-1015 HOMAIR Homeostasis Model Assessment - Insulin Resistance 5.606263 42 Week 6 6
CDISCPILOT01 01-701-1015 HOMAIR Homeostasis Model Assessment - Insulin Resistance 4.369747 63 Week 8 8
CDISCPILOT01 01-701-1015 HOMAIR Homeostasis Model Assessment - Insulin Resistance 6.675262 84 Week 12 12
CDISCPILOT01 01-701-1015 HOMAIR Homeostasis Model Assessment - Insulin Resistance 8.635382 126 Week 16 16
CDISCPILOT01 01-701-1015 HOMAIR Homeostasis Model Assessment - Insulin Resistance 3.495403 140 Week 20 20
CDISCPILOT01 01-701-1015 HOMAIR Homeostasis Model Assessment - Insulin Resistance 6.354785 168 Week 24 24
CDISCPILOT01 01-701-1015 HOMAIR Homeostasis Model Assessment - Insulin Resistance 6.854622 182 Week 26 26
CDISCPILOT01 01-701-1023 HOMAIR Homeostasis Model Assessment - Insulin Resistance 6.513173 -14 Baseline 0

Derive FLI score

To obtain the FLI score parameter, we’ll utilize triglycerides, GGT, BMI, and waist circumference. Note that this derivation requires merging data from the ADVS dataset (BMI and Waist Circumference), as demonstrated in the previous section. FLI is provided here as an example; users can derive other metabolic scores like HSI, NAFLD, and others using the same logic and required input variables.

# Derive FLI using derive_param_computed
adlb <- adlb %>%
  derive_param_computed(
    by_vars = exprs(!!!get_admiral_option("subject_keys"), AVISIT, AVISITN, ADT, ADY, BMI, WSTCIR, !!!adsl_vars),
    parameters = c("TRIG", "GGT"),
    set_values_to = exprs(
      AVAL = {
        lambda <- 0.953 * log(AVAL.TRIG) + 0.139 * BMI + 0.718 * log(AVAL.GGT) + 0.053 * WSTCIR - 15.745
        (exp(lambda) / (1 + exp(lambda))) * 100
      },
      PARAMCD = "FLI",
      PARAM = "Fatty Liver Index",
      PARAMN = 11
    )
  )

adlb <- adlb %>%
  arrange(!!!get_admiral_option("subject_keys"), ADT, PARAMN) # Arrange for consistency
STUDYID USUBJID PARAMCD PARAM AVAL ADY AVISIT AVISITN
CDISCPILOT01 01-701-1015 FLI Fatty Liver Index 77.41712 -7 Baseline 0
CDISCPILOT01 01-701-1015 FLI Fatty Liver Index 52.97118 15 Week 2 2
CDISCPILOT01 01-701-1015 FLI Fatty Liver Index 83.46849 42 Week 6 6
CDISCPILOT01 01-701-1015 FLI Fatty Liver Index 81.29596 63 Week 8 8
CDISCPILOT01 01-701-1015 FLI Fatty Liver Index 69.50608 84 Week 12 12
CDISCPILOT01 01-701-1015 FLI Fatty Liver Index 51.45346 126 Week 16 16
CDISCPILOT01 01-701-1015 FLI Fatty Liver Index 91.01194 140 Week 20 20
CDISCPILOT01 01-701-1015 FLI Fatty Liver Index 93.15697 168 Week 24 24
CDISCPILOT01 01-701-1015 FLI Fatty Liver Index 88.77355 182 Week 26 26
CDISCPILOT01 01-701-1023 FLI Fatty Liver Index 73.64499 -14 Baseline 0

Remaining ADLB Set-up

The {admiral} Creating a BDS Finding ADaM vignette describes further steps, including how to calculate baseline and change from baseline variables, add analysis flags (e.g., ANL01FL), handle reference ranges, categorizations, and other common ADLB requirements.

Example Scripts

ADaM Sample Code
ADLB ad_adlb.R

These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.