junco
Tabulation
The junco
R package provides functions to create
analyses for clinical trials in R
. It is considered as an
add-on/alternative to the tern
package, which is the first
package available in the NEST
framework for analysis
functions with main focus for clinical trials. The core functionality
for tabulation is built on the more general purpose rtables
package. New users should first begin by reading the “Introduction
to tern
” and “Introduction
to rtables
” vignettes.
The packages used in this vignette are:
The datasets used in this vignette are:
adsl <- ex_adsl
adae <- ex_adae
advs <- ex_advs
Some common data manipulation on/from these datasets, such as adding extra variables and defining some tabulation settings, like treatment variable, control group for the table.
trtvar <- "ARM"
ctrl_grp <- "B: Placebo"
non_ctrl_grp <- setdiff(levels(adsl[[trtvar]]), ctrl_grp)
adsl$colspan_trt <- factor(ifelse(adsl[[trtvar]] == ctrl_grp, " ", "Active Study Agent"),
levels = c("Active Study Agent", " ")
)
adsl$rrisk_header <- "Risk Difference (%) (95% CI)"
adsl$rrisk_label <- paste(adsl[[trtvar]], paste("vs", ctrl_grp))
adsl$rrisk_header_vs <- "Difference in Mean Change (95% CI)"
# define colspan_trt_map
colspan_trt_map <- create_colspan_map(adsl,
non_active_grp = ctrl_grp,
non_active_grp_span_lbl = " ",
active_grp_span_lbl = "Active Study Agent",
colspan_var = "colspan_trt",
trt_var = trtvar
)
# define reference group specification
ref_path <- c("colspan_trt", " ", trtvar, ctrl_grp)
adae[["TRTEMFL"]] <- "Y"
# add adsl variables to adae
adae <- adae %>% left_join(., adsl)
advs <- advs %>% left_join(., adsl)
advs[advs[["ABLFL"]] == "Y", "CHG"] <- NA
junco
Analysis Functions
The junco
analysis functions are used in combination
with the rtables
layout functions,
rtables::analyze
and
rtables::summarize_row_groups
, in the pipeline which
creates the rtables
table. They apply some statistical
logic to the layout of the rtables
table. The table layout
is materialized with the rtables::build_table
function and
the data.
The junco
analysis functions are functions that can be
applied as an afun
in either rtables::analyze
or as a cfun
in rtables::summarize_row_groups
function. This is a slightly different approach to tern
,
where the table layout is constructed using analyze
functions, which are wrappers around rtables::analyze
.
Just like tern
analyze functions, the junco
analysis functions offer various methods useful from the perspective of
clinical trials and other statistical projects.
Examples of the junco
analysis functions are
a_freq_j
, a_freq_subcol_j
,
a_summarize_aval_chg_diff_j
or
a_summarize_ex_j
.
A complete list of analysis functions can be found in the junco website functions reference.
Tabulation Examples using a_freq_j
We present an example usage of a_freq_j
for the very
common AE table in clinical trials.
The standard table of adverse events is a summary by system organ class and preferred term. For frequency counts by preferred term, if there are multiple occurrences of the same AE in an individual we count them only once.
With junco
package, this table can be created with
several calls to the same a_freq_j
function in a tabulation
pipeline using rtables::analyze
and
rtables::summarize_row_groups
.
In next paragraph, we’ll describe the difference versus using
tern
package, for similar AE table. Differences in how to
define the layout as well as differences in the resulting table.
## extra args for a_freq_j controlling specification of
## reference group, denominator used to calculate percentages,
## and other details
extra_args_rr <- list(
denom = "n_altdf",
riskdiff = TRUE,
ref_path = ref_path,
method = "wald",
.stats = c("count_unique_fraction")
)
Using junco
analysis function a_freq_j
we
define the layout, using 2 analyze
calls (for overall
summary - TRTEMFL and preferred term - AEDECOD), and 1
summarize_row_groups
call (for system organ class -
AEBODSYS)
Note that the same specifications, extra_args_rr
can be
re-used in the first and second analyze
call, as well as in
the in-between call to summarize_row_groups
.
For the overall summary, we add as extra specification to restrict to TRTEMFL = “Y” values and the label to show in the row.
lyt <- basic_table(
top_level_section_div = " ",
colcount_format = "N=xx"
) %>%
## main columns
split_cols_by("colspan_trt", split_fun = trim_levels_to_map(map = colspan_trt_map)) %>%
split_cols_by(trtvar, show_colcounts = TRUE) %>%
## risk diff columns, note nested = FALSE
split_cols_by("rrisk_header", nested = FALSE) %>%
split_cols_by(trtvar, labels_var = "rrisk_label", split_fun = remove_split_levels(ctrl_grp),
show_colcounts = FALSE
) %>%
analyze("TRTEMFL", afun = a_freq_j,
extra_args = append(extra_args_rr, list(val = "Y", label = "Number of subjects with AE"))
) %>%
split_rows_by("AEBODSYS",
split_label = "System Organ Class",
split_fun = trim_levels_in_group("AEDECOD"),
label_pos = "topleft",
section_div = c(" "),
nested = FALSE
) %>%
summarize_row_groups("AEBODSYS", cfun = a_freq_j,
extra_args = extra_args_rr
) %>%
analyze("AEDECOD", afun = a_freq_j,
extra_args = extra_args_rr
)
Now we just build and view the resulting table.
tbl <- build_table(lyt, adae, alt_counts_df = adsl)
head(tbl, 10)
#> Active Study Agent
#> A: Drug X C: Combination B: Placebo Risk Difference (%) (95% CI)
#> System Organ Class N=134 N=132 N=134 A: Drug X vs B: Placebo C: Combination vs B: Placebo
#> ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
#> Number of subjects with AE 122 (91.0%) 120 (90.9%) 123 (91.8%) -0.7 (-7.5, 6.0) -0.9 (-7.6, 5.9)
#>
#> cl A.1 78 (58.2%) 89 (67.4%) 75 (56.0%) 2.2 (-9.6, 14.1) 11.5 (-0.1, 23.1)
#> dcd A.1.1.1.1 50 (37.3%) 63 (47.7%) 45 (33.6%) 3.7 (-7.7, 15.2) 14.1 (2.5, 25.8)
#> dcd A.1.1.1.2 48 (35.8%) 50 (37.9%) 48 (35.8%) 0.0 (-11.5, 11.5) 2.1 (-9.5, 13.7)
#>
#> cl B.1 47 (35.1%) 43 (32.6%) 49 (36.6%) -1.5 (-13.0, 10.0) -4.0 (-15.4, 7.4)
#> dcd B.1.1.1.1 47 (35.1%) 43 (32.6%) 49 (36.6%) -1.5 (-13.0, 10.0) -4.0 (-15.4, 7.4)
#>
#> cl B.2 79 (59.0%) 85 (64.4%) 74 (55.2%) 3.7 (-8.1, 15.6) 9.2 (-2.6, 20.9)
#> dcd B.2.1.2.1 49 (36.6%) 52 (39.4%) 44 (32.8%) 3.7 (-7.7, 15.1) 6.6 (-5.0, 18.1)
#> dcd B.2.2.3.1 48 (35.8%) 51 (38.6%) 54 (40.3%) -4.5 (-16.1, 7.1) -1.7 (-13.4, 10.1)
#>
#> cl C.1 43 (32.1%) 43 (32.6%) 46 (34.3%) -2.2 (-13.5, 9.0) -1.8 (-13.1, 9.6)
Minor differences between current table and a similar table using
tern
analyze functions.
Here is a similar table generated with the tern functions
(summarize_occurrences
and count_occurrences
),
as close as possible to our target AE table we produced before in
tbl
.
lyt_tern <- basic_table(
top_level_section_div = " ",
colcount_format = "N=xx"
) %>%
## main columns
split_cols_by(trtvar,
show_colcounts = TRUE,
split_fun = add_riskdiff(arm_x = ctrl_grp, arm_y = non_ctrl_grp)
) %>%
analyze_num_patients(
vars = "USUBJID",
.stats = c("unique"),
.labels = c(
unique = "Total number of patients with at least one adverse event"
),
riskdiff = TRUE
) %>%
split_rows_by("AEBODSYS",
split_label = "System Organ Class",
split_fun = trim_levels_in_group("AEDECOD"),
label_pos = "topleft",
section_div = c(" "),
nested = FALSE
) %>%
summarize_occurrences(var = "AEBODSYS",
denom = "N_col",
riskdiff = TRUE,
.stats = c("count_fraction")
) %>%
count_occurrences(vars = "AEDECOD",
denom = "N_col",
riskdiff = TRUE,
.stats = c("count_fraction")
)
tbl_tern <- build_table(lyt_tern, adae, alt_counts_df = adsl)
head(tbl_tern, 10)
#> Risk Difference (%) (95% CI) Risk Difference (%) (95% CI)
#> A: Drug X B: Placebo C: Combination B: Placebo vs. A: Drug X B: Placebo vs. C: Combination
#> System Organ Class N=134 N=134 N=132 N=268 N=266
#> ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
#> Total number of patients with at least one adverse event 122 (91.0%) 123 (91.8%) 120 (90.9%) 0.7 (-6.0 - 7.5) 0.9 (-5.9 - 7.6)
#>
#> cl A.1 78 (58.2%) 75 (56%) 89 (67.4%) -2.2 (-14.1 - 9.6) -11.5 (-23.1 - 0.1)
#> dcd A.1.1.1.1 50 (37.3%) 45 (33.6%) 63 (47.7%) -3.7 (-15.2 - 7.7) -14.1 (-25.8 - -2.5)
#> dcd A.1.1.1.2 48 (35.8%) 48 (35.8%) 50 (37.9%) 0.0 (-11.5 - 11.5) -2.1 (-13.7 - 9.5)
#>
#> cl B.1 47 (35.1%) 49 (36.6%) 43 (32.6%) 1.5 (-10.0 - 13.0) 4.0 (-7.4 - 15.4)
#> dcd B.1.1.1.1 47 (35.1%) 49 (36.6%) 43 (32.6%) 1.5 (-10.0 - 13.0) 4.0 (-7.4 - 15.4)
#>
#> cl B.2 79 (59%) 74 (55.2%) 85 (64.4%) -3.7 (-15.6 - 8.1) -9.2 (-20.9 - 2.6)
#> dcd B.2.1.2.1 49 (36.6%) 44 (32.8%) 52 (39.4%) -3.7 (-15.1 - 7.7) -6.6 (-18.1 - 5.0)
#> dcd B.2.2.3.1 48 (35.8%) 54 (40.3%) 51 (38.6%) 4.5 (-7.1 - 16.1) 1.7 (-10.1 - 13.4)
#>
#> cl C.1 43 (32.1%) 46 (34.3%) 43 (32.6%) 2.2 (-9.0 - 13.5) 1.8 (-9.6 - 13.1)
The main differences in the resulting table are
- the comparison against the reference group is reversed (ie B:
Placebo vs. A: Drug X instead of A: Drug X vs. B: Placebo).
- the extra column spanner for active treatment group is not present
in the
tern
version, and cannot be added.
a_freq_j supports various methods for the risk difference column.
One of the statistical options to control with the usage of
a_freq_j
is the method for the risk difference calculation
for the risk difference columns. All methods available in
´tern::estimate_proportion_diff´ can be supported. Eg, switching to
waldcc
, or others can be done. There is no option to switch
methods using tern count_occurrences
layouts, only
wald
method is available.
extra_args_rr[["method"]] <- "waldcc"
tbl2 <- basic_table(
top_level_section_div = " ",
colcount_format = "N=xx"
) %>%
## main columns
split_cols_by("colspan_trt", split_fun = trim_levels_to_map(map = colspan_trt_map)) %>%
split_cols_by(trtvar, show_colcounts = TRUE) %>%
## risk diff columns, note nested = FALSE
split_cols_by("rrisk_header", nested = FALSE) %>%
split_cols_by(trtvar, labels_var = "rrisk_label", split_fun = remove_split_levels(ctrl_grp),
show_colcounts = FALSE) %>%
split_rows_by("AEBODSYS",
split_label = "System Organ Class",
split_fun = trim_levels_in_group("AEDECOD"),
label_pos = "topleft",
section_div = c(" "),
nested = FALSE
) %>%
summarize_row_groups("AEBODSYS", cfun = a_freq_j,
extra_args = extra_args_rr
) %>%
analyze("AEDECOD", afun = a_freq_j,
extra_args = extra_args_rr
) %>%
build_table(adae, alt_counts_df = adsl)
head(tbl2, 10)
#> Active Study Agent
#> A: Drug X C: Combination B: Placebo Risk Difference (%) (95% CI)
#> System Organ Class N=134 N=132 N=134 A: Drug X vs B: Placebo C: Combination vs B: Placebo
#> ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
#> cl A.1 78 (58.2%) 89 (67.4%) 75 (56.0%) 2.2 (-10.4, 14.8) 11.5 (-0.9, 23.8)
#> dcd A.1.1.1.1 50 (37.3%) 63 (47.7%) 45 (33.6%) 3.7 (-8.5, 15.9) 14.1 (1.7, 26.6)
#> dcd A.1.1.1.2 48 (35.8%) 50 (37.9%) 48 (35.8%) 0.0 (-12.2, 12.2) 2.1 (-10.3, 14.4)
#>
#> cl B.1 47 (35.1%) 43 (32.6%) 49 (36.6%) -1.5 (-13.7, 10.7) -4.0 (-16.2, 8.2)
#> dcd B.1.1.1.1 47 (35.1%) 43 (32.6%) 49 (36.6%) -1.5 (-13.7, 10.7) -4.0 (-16.2, 8.2)
#>
#> cl B.2 79 (59.0%) 85 (64.4%) 74 (55.2%) 3.7 (-8.9, 16.3) 9.2 (-3.3, 21.7)
#> dcd B.2.1.2.1 49 (36.6%) 52 (39.4%) 44 (32.8%) 3.7 (-8.4, 15.9) 6.6 (-5.7, 18.8)
#> dcd B.2.2.3.1 48 (35.8%) 51 (38.6%) 54 (40.3%) -4.5 (-16.8, 7.9) -1.7 (-14.2, 10.8)
#>
#> cl C.1 43 (32.1%) 43 (32.6%) 46 (34.3%) -2.2 (-14.3, 9.8) -1.8 (-13.8, 10.3)
#> dcd C.1.1.1.3 43 (32.1%) 43 (32.6%) 46 (34.3%) -2.2 (-14.3, 9.8) -1.8 (-13.8, 10.3)
Creation of Subgroup tables with a_freq_j
The junco function a_freq_j
also supports the creation
of subgroup tables, which is demonstrated in below table.
extra_args_rr_common <- list(
denom = "n_altdf",
denom_by = "SEX"
)
extra_args_rr <- append(
extra_args_rr_common,
list(
riskdiff = FALSE,
extrablankline = TRUE,
.stats = c("n_altdf"),
label_fstr = "Gender: %s"
)
)
extra_args_rr2 <- append(
extra_args_rr_common,
list(
riskdiff = TRUE,
ref_path = ref_path,
method = "wald",
.stats = c("count_unique_denom_fraction"),
na_str = rep("NA", 3)
)
)
tbl <- basic_table(
top_level_section_div = " ",
colcount_format = "N=xx"
) %>%
## main columns
split_cols_by("colspan_trt", split_fun = trim_levels_to_map(map = colspan_trt_map)) %>%
split_cols_by(trtvar, show_colcounts = TRUE) %>%
## risk diff columns, note nested = FALSE
split_cols_by("rrisk_header", nested = FALSE) %>%
split_cols_by(trtvar, labels_var = "rrisk_label", split_fun = remove_split_levels(ctrl_grp),
show_colcounts = FALSE) %>%
split_rows_by("SEX", split_fun = drop_split_levels) %>%
summarize_row_groups("SEX", cfun = a_freq_j,
extra_args = extra_args_rr
) %>%
split_rows_by("TRTEMFL",
split_fun = keep_split_levels("Y"),
indent_mod = -1L,
section_div = c(" ")
) %>%
summarize_row_groups("TRTEMFL",
cfun = a_freq_j,
extra_args = append(extra_args_rr2, list(label = "Subjects with >=1 AE", extrablankline = TRUE))
) %>%
split_rows_by("AEBODSYS",
split_label = "System Organ Class",
split_fun = trim_levels_in_group("AEDECOD"),
label_pos = "topleft",
section_div = c(" "),
nested = TRUE
) %>%
summarize_row_groups("AEBODSYS", cfun = a_freq_j,
extra_args = extra_args_rr2
) %>%
analyze("AEDECOD", afun = a_freq_j,
extra_args = extra_args_rr2
) %>%
build_table(adae, alt_counts_df = adsl)
head(tbl, 30)
#> Active Study Agent
#> A: Drug X C: Combination B: Placebo Risk Difference (%) (95% CI)
#> System Organ Class N=134 N=132 N=134 A: Drug X vs B: Placebo C: Combination vs B: Placebo
#> ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
#> Gender: F 79 66 77
#>
#> Subjects with >=1 AE 72/79 (91.1%) 61/66 (92.4%) 73/77 (94.8%) -3.7 (-11.7, 4.3) -2.4 (-10.5, 5.7)
#>
#> cl A.1 53/79 (67.1%) 42/66 (63.6%) 48/77 (62.3%) 4.8 (-10.2, 19.7) 1.3 (-14.6, 17.2)
#> dcd A.1.1.1.1 34/79 (43.0%) 32/66 (48.5%) 30/77 (39.0%) 4.1 (-11.3, 19.5) 9.5 (-6.7, 25.8)
#> dcd A.1.1.1.2 32/79 (40.5%) 24/66 (36.4%) 31/77 (40.3%) 0.2 (-15.2, 15.6) -3.9 (-19.9, 12.1)
#>
#> cl B.1 28/79 (35.4%) 21/66 (31.8%) 32/77 (41.6%) -6.1 (-21.4, 9.1) -9.7 (-25.5, 6.0)
#> dcd B.1.1.1.1 28/79 (35.4%) 21/66 (31.8%) 32/77 (41.6%) -6.1 (-21.4, 9.1) -9.7 (-25.5, 6.0)
#>
#> cl B.2 46/79 (58.2%) 40/66 (60.6%) 43/77 (55.8%) 2.4 (-13.1, 17.9) 4.8 (-11.4, 20.9)
#> dcd B.2.1.2.1 29/79 (36.7%) 19/66 (28.8%) 30/77 (39.0%) -2.3 (-17.5, 13.0) -10.2 (-25.6, 5.3)
#> dcd B.2.2.3.1 30/79 (38.0%) 24/66 (36.4%) 30/77 (39.0%) -1.0 (-16.3, 14.3) -2.6 (-18.5, 13.3)
#>
#> cl C.1 30/79 (38.0%) 25/66 (37.9%) 35/77 (45.5%) -7.5 (-22.9, 8.0) -7.6 (-23.7, 8.6)
#> dcd C.1.1.1.3 30/79 (38.0%) 25/66 (37.9%) 35/77 (45.5%) -7.5 (-22.9, 8.0) -7.6 (-23.7, 8.6)
#>
#> cl C.2 23/79 (29.1%) 28/66 (42.4%) 33/77 (42.9%) -13.7 (-28.7, 1.2) -0.4 (-16.7, 15.8)
#> dcd C.2.1.2.1 23/79 (29.1%) 28/66 (42.4%) 33/77 (42.9%) -13.7 (-28.7, 1.2) -0.4 (-16.7, 15.8)
#>
#> cl D.1 45/79 (57.0%) 39/66 (59.1%) 38/77 (49.4%) 7.6 (-8.0, 23.2) 9.7 (-6.6, 26.0)
#> dcd D.1.1.1.1 25/79 (31.6%) 26/66 (39.4%) 28/77 (36.4%) -4.7 (-19.6, 10.1) 3.0 (-12.9, 19.0)
#> dcd D.1.1.4.2 30/79 (38.0%) 26/66 (39.4%) 21/77 (27.3%) 10.7 (-3.9, 25.3) 12.1 (-3.3, 27.5)
#>
#> cl D.2 26/79 (32.9%) 32/66 (48.5%) 40/77 (51.9%) -19.0 (-34.3, -3.8) -3.5 (-19.9, 13.0)
#> dcd D.2.1.5.3 26/79 (32.9%) 32/66 (48.5%) 40/77 (51.9%) -19.0 (-34.3, -3.8) -3.5 (-19.9, 13.0)
#>
#> Gender: M 51 60 55
#>
#> Subjects with >=1 AE 46/51 (90.2%) 53/60 (88.3%) 48/55 (87.3%) 2.9 (-9.1, 14.9) 1.1 (-10.9, 13.0)
#>
#> cl A.1 24/51 (47.1%) 41/60 (68.3%) 25/55 (45.5%) 1.6 (-17.4, 20.6) 22.9 (5.2, 40.5)
#> dcd A.1.1.1.1 16/51 (31.4%) 29/60 (48.3%) 15/55 (27.3%) 4.1 (-13.2, 21.4) 21.1 (3.8, 38.3)
#> dcd A.1.1.1.2 15/51 (29.4%) 22/60 (36.7%) 15/55 (27.3%) 2.1 (-15.0, 19.3) 9.4 (-7.6, 26.3)
#>
#> cl B.1 18/51 (35.3%) 21/60 (35.0%) 16/55 (29.1%) 6.2 (-11.6, 24.0) 5.9 (-11.1, 22.9)
#> dcd B.1.1.1.1 18/51 (35.3%) 21/60 (35.0%) 16/55 (29.1%) 6.2 (-11.6, 24.0) 5.9 (-11.1, 22.9)
This table cannot be generated using the tern
count_occurrences
methods.
Other junco features : Extra Statistics have been added to some tern statistical functions
tern::get_stats("summarize_ancova")
#> [1] "n" "lsmean" "lsmean_diff" "lsmean_diff_ci"
#> [5] "pval"
tern::get_stats("analyze_vars_numeric")
#> [1] "n" "sum" "mean" "sd"
#> [5] "se" "mean_sd" "mean_se" "mean_ci"
#> [9] "mean_sei" "mean_sdi" "mean_pval" "median"
#> [13] "mad" "median_ci" "quantiles" "iqr"
#> [17] "range" "min" "max" "median_range"
#> [21] "cv" "geom_mean" "geom_sd" "geom_mean_sd"
#> [25] "geom_mean_ci" "geom_cv" "median_ci_3d" "mean_ci_3d"
#> [29] "geom_mean_ci_3d"
In junco, we have added extra stats for
- ancova: se for lsmean, combined lsmean-CI (3d stat), combined lsmean_diff-CI (3d stat)
- analyze_vars_numeric: combined version of mean-CI, median-CI, geom_mean-CI (available in tern >= 0.9.6)
- similar extra stats for Kaplan-Meier/survival and other methods
Tabulation Examples using
a_summarize_aval_chg_diff_j
multivars <- c("AVAL", "AVAL", "CHG")
extra_args_3col <- list(
format_na_str = rep(NA, 3),
ref_path = ref_path,
ancova = FALSE,
comp_btw_group = TRUE,
multivars = multivars
)
lyt_vs_p1 <- basic_table(
show_colcounts = FALSE,
colcount_format = "N=xx"
) %>%
### first columns
split_cols_by("colspan_trt",
split_fun = trim_levels_to_map(map = colspan_trt_map),
show_colcounts = FALSE
) %>%
split_cols_by(trtvar,
show_colcounts = TRUE, colcount_format = "N=xx"
) %>%
## set up a 3 column split
split_cols_by_multivar(multivars,
varlabels = c("n/N (%)", "Mean (95% CI)", "Mean Change From Baseline (95% CI)")
) %>%
split_rows_by("PARAM",
label_pos = "topleft",
split_label = "Parameter",
section_div = " ",
split_fun = drop_split_levels
) %>%
## note the child_labels = hidden for AVISIT, these labels will be taken care off by
## applying function summarize_aval_chg_diff further in the layout
split_rows_by("AVISIT",
label_pos = "topleft",
split_label = "Study Visit",
split_fun = drop_split_levels,
child_labels = "hidden"
)
lyt_vs <- lyt_vs_p1 %>%
### restart for the rrisk_header columns - note the nested = FALSE option
### also note the child_labels = "hidden" in both PARAM and AVISIT
split_cols_by("rrisk_header_vs", nested = FALSE) %>%
split_cols_by(trtvar,
split_fun = remove_split_levels(ctrl_grp),
labels_var = "rrisk_label",
show_colcounts = TRUE,
colcount_format = "N=xx"
) %>%
### difference columns : just 1 column & analysis needs to be done on change
split_cols_by_multivar(multivars[3],
varlabels = c(" ")
) %>%
### the variable passed here in analyze is not used (STUDYID), it is a dummy var passing,
### the function a_summarize_aval_chg_diff_j grabs the required vars from cols_by_multivar calls
analyze("STUDYID",
afun = a_summarize_aval_chg_diff_j,
extra_args = extra_args_3col
)
result_vs <- build_table(lyt_vs, advs, alt_counts_df = adsl)
This is the resulting table.
head(result_vs, 15)
#> Active Study Agent Difference in Mean Change (95% CI)
#> A: Drug X C: Combination B: Placebo A: Drug X vs B: Placebo C: Combination vs B: Placebo
#> Parameter N=134 N=132 N=134 N=134 N=132
#> Study Visit n/N (%) Mean (95% CI) Mean Change From Baseline (95% CI) n/N (%) Mean (95% CI) Mean Change From Baseline (95% CI) n/N (%) Mean (95% CI) Mean Change From Baseline (95% CI)
#> —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
#> Diastolic Blood Pressure
#> SCREENING 134/134 (100.0%) 50.0 (48.7, 51.2) 132/132 (100.0%) 50.2 (48.9, 51.5) 134/134 (100.0%) 50.8 (49.3, 52.2)
#> BASELINE 134/134 (100.0%) 48.6 (47.2, 50.0) 132/132 (100.0%) 51.1 (49.8, 52.4) 134/134 (100.0%) 50.4 (49.1, 51.8)
#> WEEK 1 DAY 8 134/134 (100.0%) 50.3 (49.0, 51.5) 1.7 (-0.2, 3.5) 132/132 (100.0%) 48.9 (47.5, 50.2) -2.3 (-4.0, -0.5) 134/134 (100.0%) 49.7 (48.4, 51.0) -0.8 (-2.6, 1.1) 2.4 (-0.2, 5.0) -1.5 (-4.1, 1.1)
#> WEEK 2 DAY 15 134/134 (100.0%) 50.8 (49.5, 52.2) 2.2 (0.2, 4.2) 132/132 (100.0%) 50.0 (48.5, 51.4) -1.1 (-3.1, 0.9) 134/134 (100.0%) 49.7 (48.3, 51.2) -0.7 (-2.9, 1.4) 3.0 (0.0, 5.9) -0.4 (-3.3, 2.5)
#> WEEK 3 DAY 22 134/134 (100.0%) 50.7 (49.4, 52.0) 2.1 (0.3, 4.0) 132/132 (100.0%) 49.9 (48.6, 51.3) -1.2 (-3.0, 0.7) 134/134 (100.0%) 49.1 (47.7, 50.4) -1.3 (-3.2, 0.5) 3.5 (0.8, 6.1) 0.2 (-2.5, 2.8)
#> WEEK 4 DAY 29 134/134 (100.0%) 50.1 (48.7, 51.5) 1.5 (-0.4, 3.3) 132/132 (100.0%) 49.7 (48.3, 51.1) -1.4 (-3.3, 0.5) 134/134 (100.0%) 49.6 (48.4, 50.8) -0.8 (-2.6, 1.0) 2.3 (-0.3, 4.9) -0.6 (-3.2, 2.0)
#> WEEK 5 DAY 36 134/134 (100.0%) 50.6 (49.3, 51.9) 2.0 (0.1, 3.9) 132/132 (100.0%) 49.1 (47.8, 50.4) -2.0 (-3.9, -0.2) 134/134 (100.0%) 48.4 (47.0, 49.7) -2.1 (-4.1, -0.1) 4.0 (1.3, 6.8) 0.1 (-2.6, 2.8)
#>
#> Pulse Rate
#> SCREENING 134/134 (100.0%) 49.6 (48.1, 51.1) 132/132 (100.0%) 49.3 (47.8, 50.8) 134/134 (100.0%) 49.4 (48.0, 50.8)
#> BASELINE 134/134 (100.0%) 51.9 (50.5, 53.2) 132/132 (100.0%) 50.3 (48.6, 51.9) 134/134 (100.0%) 50.3 (48.8, 51.8)
#> WEEK 1 DAY 8 134/134 (100.0%) 50.1 (48.6, 51.5) -1.8 (-3.8, 0.2) 132/132 (100.0%) 49.8 (48.5, 51.1) -0.5 (-2.6, 1.7) 134/134 (100.0%) 49.3 (48.0, 50.6) -1.0 (-3.0, 1.0) -0.8 (-3.6, 2.0) 0.5 (-2.4, 3.5)
#> WEEK 2 DAY 15 134/134 (100.0%) 49.7 (48.2, 51.2) -2.2 (-4.3, 0.0) 132/132 (100.0%) 49.1 (47.7, 50.4) -1.2 (-3.1, 0.8) 134/134 (100.0%) 50.8 (49.5, 52.1) 0.6 (-1.5, 2.6) -2.7 (-5.6, 0.2) -1.8 (-4.5, 1.0)
#> WEEK 3 DAY 22 134/134 (100.0%) 50.5 (49.2, 51.7) -1.4 (-3.3, 0.5) 132/132 (100.0%) 49.8 (48.6, 51.0) -0.5 (-2.5, 1.6) 134/134 (100.0%) 49.9 (48.6, 51.3) -0.4 (-2.2, 1.5) -1.1 (-3.7, 1.6) -0.1 (-2.9, 2.7)
#> WEEK 4 DAY 29 134/134 (100.0%) 49.0 (47.5, 50.4) -2.9 (-4.8, -1.0) 132/132 (100.0%) 51.0 (49.7, 52.3) 0.7 (-1.3, 2.7) 134/134 (100.0%) 50.0 (48.5, 51.4) -0.3 (-2.4, 1.7) -2.6 (-5.4, 0.2) 1.0 (-1.8, 3.9)
The columns for the comparison between reference group is optional.
The same table without these extra columns can be produced by specifying
the argument comp_btw_group
= FALSE
and
leaving out the 3 split_cols_by
calls
- split_cols_by(“rrisk_header_vs”)
- split_cols_by(trtvar)
- split_cols_by_multivar(multivars[3])
multivars <- c("AVAL", "AVAL", "CHG")
extra_args_3col <- list(
format_na_str = rep(NA, 3),
ancova = FALSE,
comp_btw_group = FALSE,
multivars = multivars
)
lyt_vs2 <- lyt_vs_p1 %>%
### the variable passed here in analyze is not used (STUDYID), it is a dummy var passing,
### the function a_summarize_aval_chg_diff_j grabs the required vars from cols_by_multivar calls
analyze("STUDYID",
afun = a_summarize_aval_chg_diff_j,
extra_args = extra_args_3col
)
result_vs2 <- build_table(lyt_vs2, advs, alt_counts_df = adsl)
This is the resulting table without the difference between treatment group columns.
head(result_vs2, 15)
#> Active Study Agent
#> A: Drug X C: Combination B: Placebo
#> Parameter N=134 N=132 N=134
#> Study Visit n/N (%) Mean (95% CI) Mean Change From Baseline (95% CI) n/N (%) Mean (95% CI) Mean Change From Baseline (95% CI) n/N (%) Mean (95% CI) Mean Change From Baseline (95% CI)
#> ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
#> Diastolic Blood Pressure
#> SCREENING 134/134 (100.0%) 50.0 (48.7, 51.2) 132/132 (100.0%) 50.2 (48.9, 51.5) 134/134 (100.0%) 50.8 (49.3, 52.2)
#> BASELINE 134/134 (100.0%) 48.6 (47.2, 50.0) 132/132 (100.0%) 51.1 (49.8, 52.4) 134/134 (100.0%) 50.4 (49.1, 51.8)
#> WEEK 1 DAY 8 134/134 (100.0%) 50.3 (49.0, 51.5) 1.7 (-0.2, 3.5) 132/132 (100.0%) 48.9 (47.5, 50.2) -2.3 (-4.0, -0.5) 134/134 (100.0%) 49.7 (48.4, 51.0) -0.8 (-2.6, 1.1)
#> WEEK 2 DAY 15 134/134 (100.0%) 50.8 (49.5, 52.2) 2.2 (0.2, 4.2) 132/132 (100.0%) 50.0 (48.5, 51.4) -1.1 (-3.1, 0.9) 134/134 (100.0%) 49.7 (48.3, 51.2) -0.7 (-2.9, 1.4)
#> WEEK 3 DAY 22 134/134 (100.0%) 50.7 (49.4, 52.0) 2.1 (0.3, 4.0) 132/132 (100.0%) 49.9 (48.6, 51.3) -1.2 (-3.0, 0.7) 134/134 (100.0%) 49.1 (47.7, 50.4) -1.3 (-3.2, 0.5)
#> WEEK 4 DAY 29 134/134 (100.0%) 50.1 (48.7, 51.5) 1.5 (-0.4, 3.3) 132/132 (100.0%) 49.7 (48.3, 51.1) -1.4 (-3.3, 0.5) 134/134 (100.0%) 49.6 (48.4, 50.8) -0.8 (-2.6, 1.0)
#> WEEK 5 DAY 36 134/134 (100.0%) 50.6 (49.3, 51.9) 2.0 (0.1, 3.9) 132/132 (100.0%) 49.1 (47.8, 50.4) -2.0 (-3.9, -0.2) 134/134 (100.0%) 48.4 (47.0, 49.7) -2.1 (-4.1, -0.1)
#>
#> Pulse Rate
#> SCREENING 134/134 (100.0%) 49.6 (48.1, 51.1) 132/132 (100.0%) 49.3 (47.8, 50.8) 134/134 (100.0%) 49.4 (48.0, 50.8)
#> BASELINE 134/134 (100.0%) 51.9 (50.5, 53.2) 132/132 (100.0%) 50.3 (48.6, 51.9) 134/134 (100.0%) 50.3 (48.8, 51.8)
#> WEEK 1 DAY 8 134/134 (100.0%) 50.1 (48.6, 51.5) -1.8 (-3.8, 0.2) 132/132 (100.0%) 49.8 (48.5, 51.1) -0.5 (-2.6, 1.7) 134/134 (100.0%) 49.3 (48.0, 50.6) -1.0 (-3.0, 1.0)
#> WEEK 2 DAY 15 134/134 (100.0%) 49.7 (48.2, 51.2) -2.2 (-4.3, 0.0) 132/132 (100.0%) 49.1 (47.7, 50.4) -1.2 (-3.1, 0.8) 134/134 (100.0%) 50.8 (49.5, 52.1) 0.6 (-1.5, 2.6)
#> WEEK 3 DAY 22 134/134 (100.0%) 50.5 (49.2, 51.7) -1.4 (-3.3, 0.5) 132/132 (100.0%) 49.8 (48.6, 51.0) -0.5 (-2.5, 1.6) 134/134 (100.0%) 49.9 (48.6, 51.3) -0.4 (-2.2, 1.5)
#> WEEK 4 DAY 29 134/134 (100.0%) 49.0 (47.5, 50.4) -2.9 (-4.8, -1.0) 132/132 (100.0%) 51.0 (49.7, 52.3) 0.7 (-1.3, 2.7) 134/134 (100.0%) 50.0 (48.5, 51.4) -0.3 (-2.4, 1.7)