# load libraries
library(cards)LBT01 - Laboratory Results
Laboratory Test Results and Change from Baseline by Visit (LBT01) QC Workflow
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.
- Rename
group3andgroup3_level, togroup1andgroup1_level(contains “ARM” values). - Rename
group1andgroup1_level, togroup2andgroup2_level(contains “PARAMCD” values). - Rename
group2andgroup2_level, togroup3andgroup3_level(contains “AVISIT” values). - Recode
statnvalue toNto match ARD - 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.
- Select columns relevant to comparison
- Convert any
NaNstats toNAto 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!