# 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
<- chevron::lbt01_main(chevron::syn_data, lbl_overall = "Overall ARM")
tlg_lbt01 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::as_result_df(tlg_lbt01, make_ard = TRUE, add_tbl_str_decimals = FALSE) rtables_result
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.
<- chevron::syn_data$adlb
adlb
<- ard_continuous(adlb,
ard_result 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_continuous(adlb,
ard_overall 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
group3
andgroup3_level
, togroup1
andgroup1_level
(contains “ARM” values). - Rename
group1
andgroup1_level
, togroup2
andgroup2_level
(contains “PARAMCD” values). - Rename
group2
andgroup2_level
, togroup3
andgroup3_level
(contains “AVISIT” values). - Recode
stat
n
value toN
to 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 ::mutate(
dplyrstat_name = dplyr::recode(stat_name, "n" = "N"),
group4_level = dplyr::recode(group4_level,
"Analysis Value" = "AVAL",
"Absolute Change from Baseline" = "CHG"
)|>
) ::rename(
dplyrvariable = group4_level,
# giving a dummy name for this column so it doesn't interfere with the column renaming
val = variable
|>
) ::select(c(group1, group1_level, group2, group2_level, group3, group3_level, variable, stat_name, stat))
dplyr
<- rtables_result |>
rtables_result_overall ::filter(group3_level == "Overall ARM") |>
dplyr::select(c(group1, group1_level, group2, group2_level, variable, stat_name, stat))
dplyr
# remove the overall observations from the results df
<- rtables_result |>
rtables_result ::filter(group3_level != "Overall ARM") dplyr
ARD reformat
We’ll also need some format adjustments for the ARD object.
- Select columns relevant to comparison
- Convert any
NaN
stats toNA
to match {rtables}
<- ard_result |>
ard_result ::select(c(group1, group1_level, group2, group2_level, group3, group3_level, variable, stat_name, stat)) |>
dplyr::mutate(
dplyrstat = dplyr::recode(stat, `NaN` = NA_real_)
)
# to the overall ard_result, rename the cols to match the rtables df
<- ard_overall |>
ard_overall ::mutate(
dplyr# group1 = "ACTARM",
# group1_level = "Overall ARM",
stat = dplyr::recode(stat, `NaN` = NA_real_)
|>
) ::select(c(group1, group1_level, group2, group2_level, variable, stat_name, stat))
dplyr
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(ard_result,
diffdf
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(ard_overall,
diffdf
rtables_result_overall,keys = c("group1", "group1_level", "group2", "group2_level", "variable", "stat_name", "stat"),
suppress_warnings = TRUE
)
No issues were found!