LBT01 - Laboratory Results

Laboratory Test Results and Change from Baseline by Visit (LBT01) QC Workflow

# load libraries
library(cards)

1. Generate a table using {chevron}

Using the lbt01_main() function from the {chevron} package to generate a Lab Results Table. We’ll add an overall column to walk through the QCing steps if your table has one.

Show the code
# Create a table using the chevron package
tlg_lbt01 <- chevron::lbt01_main(chevron::syn_data, lbl_overall = "Overall ARM")
head(tlg_lbt01, n = 15)
                                                          A: Drug X                                        B: Placebo                                      C: Combination                                     Overall ARM                  
                                       Analysis Value    Absolute Change from Baseline   Analysis Value    Absolute Change from Baseline   Analysis Value   Absolute Change from Baseline   Analysis Value    Absolute Change from Baseline
                                           (N=15)                   (N=15)                   (N=15)                   (N=15)                   (N=15)                  (N=15)                   (N=45)                   (N=45)            
———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
Alanine Aminotransferase Measurement                                                                                                                                                                                                       
  SCREENING                                                                                                                                                                                                                                
    n                                        15                        0                       15                        0                       15                       0                       45                        0              
    Mean (SD)                          15.746 (7.382)               NE (NE)              21.443 (9.716)               NE (NE)              21.234 (6.314)              NE (NE)              19.474 (8.196)               NE (NE)           
    Median                                 15.466                     NE                     23.567                     NE                     22.179                    NE                     21.295                     NE              
    Min - Max                           3.29 - 29.00                NE - NE               1.89 - 33.95                NE - NE               9.64 - 31.59               NE - NE               1.89 - 33.95                NE - NE           
  BASELINE                                                                                                                                                                                                                                 
    n                                        15                                                15                                                15                                               45                                       
    Mean (SD)                          18.655 (12.455)                                   16.835 (11.080)                                   22.385 (9.452)                                   19.292 (11.059)                                
    Median                                 16.040                                            17.453                                            25.250                                           18.691                                     
    Min - Max                           2.43 - 44.06                                      1.48 - 31.99                                      0.57 - 37.23                                     0.57 - 44.06                                  
  WEEK 1 DAY 8                                                                                                                                                                                                                             
    n                                        15                       15                       15                       15                       15                      15                       45                       45              
    Mean (SD)                          16.308 (10.850)          -2.348 (17.558)          22.055 (7.537)           5.220 (16.359)           19.574 (9.876)          -2.811 (10.902)          19.313 (9.604)           0.020 (15.327)        
    Median                                 14.664                   -5.369                   22.476                    7.252                   19.425                  -0.995                   19.198                   -0.995            

2. Flatten the table into a data.frame

A {rtables} based output can be flattened into a data frame using the as_results_df() function from the {rtables package}. The make_ard argument set to TRUE, will format the data similar to the output generated by the {cards}/{cardx} package. Setting the add_tbl_str_decimals to FALSE will not return a column with the statistic as a formatted string.

rtables_result <- rtables::as_result_df(tlg_lbt01, make_ard = TRUE, add_tbl_str_decimals = FALSE)

3. Create a comparable ARD

Using the ard_continuous function, we will compute the lab results statistics. Notice how there are multiple variables specified by strata: observations will be grouped in that sequence before calculating the statistics for the variables listed in variables. The strata parameter calculates statistics for observed levels only. If your table keeps unobserved levels during calculation, the strata parameter should be replaced with the by parameter (more detail described in the documentation here).

To calculate the statistics for the overall column, the code should look similar to the prior calculation with the “ARM” variable removed from the strata (or by) parameter (indicating the data is not stratified by “ARM”).

We’ll keep the stats for the overall column in a separate data.frame to generalize this workflow.

adlb <- chevron::syn_data$adlb

ard_result <- ard_continuous(adlb,
  strata = c(PARAMCD, AVISIT, ACTARM),
  variables = c(AVAL, CHG),
  statistic =
    list(everything() ~ continuous_summary_fns(c("N", "mean", "sd", "median", "min", "max")))
) |>
  apply_fmt_fn() |>
  unlist_ard_columns()


# calculate overall statistics
ard_overall <- ard_continuous(adlb,
  strata = c(PARAMCD, AVISIT), # note arm var is removed
  variables = c(AVAL, CHG),
  statistic =
    list(everything() ~ continuous_summary_fns(c("N", "mean", "sd", "median", "min", "max")))
) |>
  apply_fmt_fn() |>
  unlist_ard_columns()

4.Statistics comparison

{rtables} reformat

Some reformatting is required to ensure the resulting data.frames are compatible. Most of the reformatting is adjusting the column names to match that of the ARD result.

  1. Rename group3 and group3_level, to group1 and group1_level (contains “ARM” values).
  2. Rename group1 and group1_level, to group2 and group2_level (contains “PARAMCD” values).
  3. Rename group2 and group2_level, to group3 and group3_level (contains “AVISIT” values).
  4. Recode stat n value to N to match ARD
  5. Select columns relevant to comparison

We’ll also separate the statistics related to the overall ARM to match the ard_overall object.

rtables_result <- rtables_result |>
  dplyr::mutate(
    stat_name = dplyr::recode(stat_name, "n" = "N"),
    group4_level = dplyr::recode(group4_level,
      "Analysis Value" = "AVAL",
      "Absolute Change from Baseline" = "CHG"
    )
  ) |>
  dplyr::rename(
    variable = group4_level,
    # giving a dummy name for this column so it doesn't interfere with the column renaming
    val = variable
  ) |>
  dplyr::select(c(group1, group1_level, group2, group2_level, group3, group3_level, variable, stat_name, stat))

rtables_result_overall <- rtables_result |>
  dplyr::filter(group3_level == "Overall ARM") |>
  dplyr::select(c(group1, group1_level, group2, group2_level, variable, stat_name, stat))

# remove the overall observations from the results df
rtables_result <- rtables_result |>
  dplyr::filter(group3_level != "Overall ARM")

ARD reformat

We’ll also need some format adjustments for the ARD object.

  1. Select columns relevant to comparison
  2. Convert any NaN stats to NA to match {rtables}
ard_result <- ard_result |>
  dplyr::select(c(group1, group1_level, group2, group2_level, group3, group3_level, variable, stat_name, stat)) |>
  dplyr::mutate(
    stat = dplyr::recode(stat, `NaN` = NA_real_)
  )

# to the overall ard_result, rename the cols to match the rtables df

ard_overall <- ard_overall |>
  dplyr::mutate(
    # group1 = "ACTARM",
    # group1_level = "Overall ARM",
    stat = dplyr::recode(stat, `NaN` = NA_real_)
  ) |>
  dplyr::select(c(group1, group1_level, group2, group2_level, variable, stat_name, stat))

head(ard_result, n = 10)
group1 group1_level group2 group2_level group3 group3_level variable stat_name stat
PARAMCD ALT AVISIT SCREENING ACTARM A: Drug X AVAL N 15.000000
PARAMCD ALT AVISIT SCREENING ACTARM A: Drug X AVAL mean 15.745666
PARAMCD ALT AVISIT SCREENING ACTARM A: Drug X AVAL sd 7.381973
PARAMCD ALT AVISIT SCREENING ACTARM A: Drug X AVAL median 15.466383
PARAMCD ALT AVISIT SCREENING ACTARM A: Drug X AVAL min 3.292476
PARAMCD ALT AVISIT SCREENING ACTARM A: Drug X AVAL max 29.000254
PARAMCD ALT AVISIT SCREENING ACTARM A: Drug X CHG N 0.000000
PARAMCD ALT AVISIT SCREENING ACTARM A: Drug X CHG mean NA
PARAMCD ALT AVISIT SCREENING ACTARM A: Drug X CHG sd NA
PARAMCD ALT AVISIT SCREENING ACTARM A: Drug X CHG median NA

Compare programmatically

Use the {diffdf} package to compare the results.

diffdf::diffdf(ard_result,
  rtables_result,
  keys = c("group1", "group1_level", "group2", "group2_level", "group3", "group3_level", "variable", "stat_name", "stat"),
  suppress_warnings = TRUE
)
No issues were found!

Compare the overall_arm

diffdf::diffdf(ard_overall,
  rtables_result_overall,
  keys = c("group1", "group1_level", "group2", "group2_level", "variable", "stat_name", "stat"),
  suppress_warnings = TRUE
)
No issues were found!