Skip to contents

[Stable]

Comparison with a reference group for different x objects.

Usage

s_compare(x, .ref_group, .in_ref_col, ...)

# S3 method for numeric
s_compare(x, .ref_group, .in_ref_col, ...)

# S3 method for factor
s_compare(x, .ref_group, .in_ref_col, denom = "n", na.rm = TRUE, ...)

# S3 method for character
s_compare(
  x,
  .ref_group,
  .in_ref_col,
  denom = "n",
  na.rm = TRUE,
  .var,
  verbose = TRUE,
  ...
)

# S3 method for logical
s_compare(x, .ref_group, .in_ref_col, na.rm = TRUE, denom = "n", ...)

a_compare(x, .ref_group, .in_ref_col, ..., .var)

# S3 method for numeric
a_compare(x, .ref_group, .in_ref_col, ...)

# S3 method for factor
a_compare(x, .ref_group, .in_ref_col, denom = "n", na.rm = TRUE, ...)

# S3 method for character
a_compare(
  x,
  .ref_group,
  .in_ref_col,
  denom = "n",
  na.rm = TRUE,
  .var,
  verbose = TRUE,
  ...
)

# S3 method for logical
a_compare(x, .ref_group, .in_ref_col, na.rm = TRUE, denom = "n", ...)

compare_vars(
  lyt,
  vars,
  var_labels = vars,
  nested = TRUE,
  ...,
  na_level = NA_character_,
  show_labels = "default",
  table_names = vars,
  .stats = c("n", "mean_sd", "count_fraction", "pval"),
  .formats = NULL,
  .labels = NULL,
  .indent_mods = NULL
)

Arguments

x

(numeric)
vector of numbers we want to analyze.

.ref_group

(data.frame or vector)
the data corresponding to the reference group.

.in_ref_col

(logical)
TRUE when working with the reference level, FALSE otherwise.

...

arguments passed to s_compare().

denom

(string)
choice of denominator for factor proportions, can only be n (number of values in this row and column intersection).

na.rm

(flag)
whether NA values should be removed from x prior to analysis.

.var

(string)
single variable name that is passed by rtables when requested by a statistics function.

verbose

(logical)
Whether warnings and messages should be printed. Mainly used to print out information about factor casting. Defaults to TRUE.

lyt

(layout)
input layout where analyses will be added to.

vars

(character)
variable names for the primary analysis variable to be iterated over.

var_labels

(character)
character for label.

nested

(flag)
whether this layout instruction be applied within the existing layout structure if possible (TRUE, the default) or as a new top-level element (FALSE). Ignored if it would nest a split underneath analyses, which is not allowed.

na_level

(string)
string used to replace all NA or empty values in the output.

show_labels

(string)
label visibility: one of "default", "visible" and "hidden".

table_names

(character)
this can be customized in case that the same vars are analyzed multiple times, to avoid warnings from rtables.

.stats

(character)
statistics to select for the table.

.formats

(named character or list)
formats for the statistics.

.labels

(named character)
labels for the statistics (without indent).

.indent_mods

(named vector of integer)
indent modifiers for the labels. Each element of the vector should be a name-value pair with name corresponding to a statistic specified in .stats and value the indentation for that statistic's row label.

Value

  • s_compare() returns output of s_summary() and comparisons versus the reference group in the form of p-values.

  • compare_vars() returns a layout object suitable for passing to further layouting functions, or to rtables::build_table(). Adding this function to an rtable layout will add formatted rows containing the statistics from s_compare() to the table layout.

Functions

  • s_compare(): S3 generic function to produce a comparison summary.

  • s_compare(numeric): Method for numeric class. This uses the standard t-test to calculate the p-value.

  • s_compare(factor): Method for factor class. This uses the chi-squared test to calculate the p-value.

  • s_compare(character): Method for character class. This makes an automatic conversion to factor (with a warning) and then forwards to the method for factors.

  • s_compare(logical): Method for logical class. A chi-squared test is used. If missing values are not removed, then they are counted as FALSE.

  • a_compare(): Formatted analysis function which is used as afun in compare_vars().

  • a_compare(numeric): Formatted analysis function method for numeric class.

  • a_compare(factor): Formatted analysis function method for factor class.

  • a_compare(character): Formatted analysis function method for character class.

  • a_compare(logical): Formatted analysis function method for logical class.

  • compare_vars(): Layout-creating function which can take statistics function arguments and additional format arguments. This function is a wrapper for rtables::analyze().

Note

  • For factor variables, denom for factor proportions can only be n since the purpose is to compare proportions between columns, therefore a row-based proportion would not make sense. Proportion based on N_col would be difficult since we use counts for the chi-squared test statistic, therefore missing values should be accounted for as explicit factor levels.

  • If factor variables contain NA, these NA values are excluded by default. To include NA values set na.rm = FALSE and missing values will be displayed as an NA level. Alternatively, an explicit factor level can be defined for NA values during pre-processing via df_explicit_na() - the default na_level ("<Missing>") will also be excluded when na.rm is set to TRUE.

  • For character variables, automatic conversion to factor does not guarantee that the table will be generated correctly. In particular for sparse tables this very likely can fail. Therefore it is always better to manually convert character variables to factors during pre-processing.

  • For compare_vars(), the column split must define a reference group via ref_group so that the comparison is well defined.

See also

Relevant constructor function create_afun_compare(), and s_summary() which is used internally to compute a summary within s_compare().

Examples

# `s_compare.numeric`

## Usual case where both this and the reference group vector have more than 1 value.
s_compare(rnorm(10, 5, 1), .ref_group = rnorm(5, -5, 1), .in_ref_col = FALSE)
#> $n
#>  n 
#> 10 
#> 
#> $sum
#>      sum 
#> 54.36803 
#> 
#> $mean
#>     mean 
#> 5.436803 
#> 
#> $sd
#>       sd 
#> 1.130201 
#> 
#> $se
#>        se 
#> 0.3574008 
#> 
#> $mean_sd
#>     mean       sd 
#> 5.436803 1.130201 
#> 
#> $mean_se
#>      mean        se 
#> 5.4368028 0.3574008 
#> 
#> $mean_ci
#> mean_ci_lwr mean_ci_upr 
#>    4.628306    6.245300 
#> attr(,"label")
#> [1] "Mean 95% CI"
#> 
#> $mean_sei
#> mean_sei_lwr mean_sei_upr 
#>     5.079402     5.794204 
#> attr(,"label")
#> [1] "Mean -/+ 1xSE"
#> 
#> $mean_sdi
#> mean_sdi_lwr mean_sdi_upr 
#>     4.306602     6.567003 
#> attr(,"label")
#> [1] "Mean -/+ 1xSD"
#> 
#> $mean_pval
#>      p_value 
#> 9.985529e-08 
#> attr(,"label")
#> [1] "Mean p-value (H0: mean = 0)"
#> 
#> $median
#>   median 
#> 5.297146 
#> 
#> $mad
#> mad 
#>   0 
#> 
#> $median_ci
#> median_ci_lwr median_ci_upr 
#>      4.262404      6.880353 
#> attr(,"conf_level")
#> [1] 0.9785156
#> attr(,"label")
#> [1] "Median 95% CI"
#> 
#> $quantiles
#> quantile_0.25 quantile_0.75 
#>      4.284343      6.380825 
#> attr(,"label")
#> [1] "25% and 75%-ile"
#> 
#> $iqr
#>      iqr 
#> 2.096482 
#> 
#> $range
#>      min      max 
#> 3.965917 7.031892 
#> 
#> $min
#>      min 
#> 3.965917 
#> 
#> $max
#>      max 
#> 7.031892 
#> 
#> $median_range
#>   median      min      max 
#> 5.297146 3.965917 7.031892 
#> attr(,"label")
#> [1] "Median (Min - Max)"
#> 
#> $cv
#>       cv 
#> 20.78796 
#> 
#> $geom_mean
#> geom_mean 
#>  5.330778 
#> 
#> $geom_mean_ci
#> mean_ci_lwr mean_ci_upr 
#>    4.587579    6.194376 
#> attr(,"label")
#> [1] "Geometric Mean 95% CI"
#> 
#> $geom_cv
#>  geom_cv 
#> 21.22207 
#> 
#> $pval
#> [1] 1.593523e-12
#> 

## If one group has not more than 1 value, then p-value is not calculated.
s_compare(rnorm(10, 5, 1), .ref_group = 1, .in_ref_col = FALSE)
#> $n
#>  n 
#> 10 
#> 
#> $sum
#>      sum 
#> 50.51729 
#> 
#> $mean
#>     mean 
#> 5.051729 
#> 
#> $sd
#>      sd 
#> 1.01919 
#> 
#> $se
#>        se 
#> 0.3222962 
#> 
#> $mean_sd
#>     mean       sd 
#> 5.051729 1.019190 
#> 
#> $mean_se
#>      mean        se 
#> 5.0517285 0.3222962 
#> 
#> $mean_ci
#> mean_ci_lwr mean_ci_upr 
#>    4.322644    5.780813 
#> attr(,"label")
#> [1] "Mean 95% CI"
#> 
#> $mean_sei
#> mean_sei_lwr mean_sei_upr 
#>     4.729432     5.374025 
#> attr(,"label")
#> [1] "Mean -/+ 1xSE"
#> 
#> $mean_sdi
#> mean_sdi_lwr mean_sdi_upr 
#>     4.032539     6.070918 
#> attr(,"label")
#> [1] "Mean -/+ 1xSD"
#> 
#> $mean_pval
#>      p_value 
#> 7.696091e-08 
#> attr(,"label")
#> [1] "Mean p-value (H0: mean = 0)"
#> 
#> $median
#>   median 
#> 5.012763 
#> 
#> $mad
#> mad 
#>   0 
#> 
#> $median_ci
#> median_ci_lwr median_ci_upr 
#>      4.220646      5.881742 
#> attr(,"conf_level")
#> [1] 0.9785156
#> attr(,"label")
#> [1] "Median 95% CI"
#> 
#> $quantiles
#> quantile_0.25 quantile_0.75 
#>      4.654216      5.817613 
#> attr(,"label")
#> [1] "25% and 75%-ile"
#> 
#> $iqr
#>      iqr 
#> 1.163397 
#> 
#> $range
#>      min      max 
#> 3.038109 6.787937 
#> 
#> $min
#>      min 
#> 3.038109 
#> 
#> $max
#>      max 
#> 6.787937 
#> 
#> $median_range
#>   median      min      max 
#> 5.012763 3.038109 6.787937 
#> attr(,"label")
#> [1] "Median (Min - Max)"
#> 
#> $cv
#>       cv 
#> 20.17507 
#> 
#> $geom_mean
#> geom_mean 
#>  4.950531 
#> 
#> $geom_mean_ci
#> mean_ci_lwr mean_ci_upr 
#>    4.233941    5.788404 
#> attr(,"label")
#> [1] "Geometric Mean 95% CI"
#> 
#> $geom_cv
#>  geom_cv 
#> 22.12155 
#> 
#> $pval
#> character(0)
#> 

## Empty numeric does not fail, it returns NA-filled items and no p-value.
s_compare(numeric(), .ref_group = numeric(), .in_ref_col = FALSE)
#> $n
#> n 
#> 0 
#> 
#> $sum
#> sum 
#>  NA 
#> 
#> $mean
#> mean 
#>   NA 
#> 
#> $sd
#> sd 
#> NA 
#> 
#> $se
#> se 
#> NA 
#> 
#> $mean_sd
#> mean   sd 
#>   NA   NA 
#> 
#> $mean_se
#> mean   se 
#>   NA   NA 
#> 
#> $mean_ci
#> mean_ci_lwr mean_ci_upr 
#>          NA          NA 
#> attr(,"label")
#> [1] "Mean 95% CI"
#> 
#> $mean_sei
#> mean_sei_lwr mean_sei_upr 
#>           NA           NA 
#> attr(,"label")
#> [1] "Mean -/+ 1xSE"
#> 
#> $mean_sdi
#> mean_sdi_lwr mean_sdi_upr 
#>           NA           NA 
#> attr(,"label")
#> [1] "Mean -/+ 1xSD"
#> 
#> $mean_pval
#> p_value 
#>      NA 
#> attr(,"label")
#> [1] "Mean p-value (H0: mean = 0)"
#> 
#> $median
#> median 
#>     NA 
#> 
#> $mad
#> mad 
#>  NA 
#> 
#> $median_ci
#> median_ci_lwr median_ci_upr 
#>            NA            NA 
#> attr(,"conf_level")
#> [1] NA
#> attr(,"label")
#> [1] "Median 95% CI"
#> 
#> $quantiles
#> quantile_0.25 quantile_0.75 
#>            NA            NA 
#> attr(,"label")
#> [1] "25% and 75%-ile"
#> 
#> $iqr
#> iqr 
#>  NA 
#> 
#> $range
#> min max 
#>  NA  NA 
#> 
#> $min
#> min 
#>  NA 
#> 
#> $max
#> max 
#>  NA 
#> 
#> $median_range
#> median    min    max 
#>     NA     NA     NA 
#> attr(,"label")
#> [1] "Median (Min - Max)"
#> 
#> $cv
#> cv 
#> NA 
#> 
#> $geom_mean
#> geom_mean 
#>       NaN 
#> 
#> $geom_mean_ci
#> mean_ci_lwr mean_ci_upr 
#>          NA          NA 
#> attr(,"label")
#> [1] "Geometric Mean 95% CI"
#> 
#> $geom_cv
#> geom_cv 
#>      NA 
#> 
#> $pval
#> character(0)
#> 

# `s_compare.factor`

## Basic usage:
x <- factor(c("a", "a", "b", "c", "a"))
y <- factor(c("a", "b", "c"))
s_compare(x = x, .ref_group = y, .in_ref_col = FALSE)
#> $n
#> [1] 5
#> 
#> $count
#> $count$a
#> [1] 3
#> 
#> $count$b
#> [1] 1
#> 
#> $count$c
#> [1] 1
#> 
#> 
#> $count_fraction
#> $count_fraction$a
#> [1] 3.0 0.6
#> 
#> $count_fraction$b
#> [1] 1.0 0.2
#> 
#> $count_fraction$c
#> [1] 1.0 0.2
#> 
#> 
#> $n_blq
#> [1] 0
#> 
#> $pval
#> [1] 0.7659283
#> 

## Management of NA values.
x <- explicit_na(factor(c("a", "a", "b", "c", "a", NA, NA)))
y <- explicit_na(factor(c("a", "b", "c", NA)))
s_compare(x = x, .ref_group = y, .in_ref_col = FALSE, na.rm = TRUE)
#> $n
#> [1] 5
#> 
#> $count
#> $count$a
#> [1] 3
#> 
#> $count$b
#> [1] 1
#> 
#> $count$c
#> [1] 1
#> 
#> 
#> $count_fraction
#> $count_fraction$a
#> [1] 3.0 0.6
#> 
#> $count_fraction$b
#> [1] 1.0 0.2
#> 
#> $count_fraction$c
#> [1] 1.0 0.2
#> 
#> 
#> $n_blq
#> [1] 0
#> 
#> $pval
#> [1] 0.7659283
#> 
s_compare(x = x, .ref_group = y, .in_ref_col = FALSE, na.rm = FALSE)
#> $n
#> [1] 7
#> 
#> $count
#> $count$a
#> [1] 3
#> 
#> $count$b
#> [1] 1
#> 
#> $count$c
#> [1] 1
#> 
#> $count$`<Missing>`
#> [1] 2
#> 
#> 
#> $count_fraction
#> $count_fraction$a
#> [1] 3.0000000 0.4285714
#> 
#> $count_fraction$b
#> [1] 1.0000000 0.1428571
#> 
#> $count_fraction$c
#> [1] 1.0000000 0.1428571
#> 
#> $count_fraction$`<Missing>`
#> [1] 2.0000000 0.2857143
#> 
#> 
#> $n_blq
#> [1] 0
#> 
#> $pval
#> [1] 0.9063036
#> 

# `s_compare.character`

## Basic usage:
x <- c("a", "a", "b", "c", "a")
y <- c("a", "b", "c")
s_compare(x, .ref_group = y, .in_ref_col = FALSE, .var = "x", verbose = FALSE)
#> $n
#> [1] 5
#> 
#> $count
#> $count$a
#> [1] 3
#> 
#> $count$b
#> [1] 1
#> 
#> $count$c
#> [1] 1
#> 
#> 
#> $count_fraction
#> $count_fraction$a
#> [1] 3.0 0.6
#> 
#> $count_fraction$b
#> [1] 1.0 0.2
#> 
#> $count_fraction$c
#> [1] 1.0 0.2
#> 
#> 
#> $n_blq
#> [1] 0
#> 
#> $pval
#> [1] 0.7659283
#> 

## Note that missing values handling can make a large difference:
x <- c("a", "a", "b", "c", "a", NA)
y <- c("a", "b", "c", rep(NA, 20))
s_compare(x,
  .ref_group = y, .in_ref_col = FALSE,
  .var = "x", verbose = FALSE
)
#> $n
#> [1] 5
#> 
#> $count
#> $count$a
#> [1] 3
#> 
#> $count$b
#> [1] 1
#> 
#> $count$c
#> [1] 1
#> 
#> 
#> $count_fraction
#> $count_fraction$a
#> [1] 3.0 0.6
#> 
#> $count_fraction$b
#> [1] 1.0 0.2
#> 
#> $count_fraction$c
#> [1] 1.0 0.2
#> 
#> 
#> $n_blq
#> [1] 0
#> 
#> $pval
#> [1] 0.7659283
#> 
s_compare(x,
  .ref_group = y, .in_ref_col = FALSE, .var = "x",
  na.rm = FALSE, verbose = FALSE
)
#> $n
#> [1] 6
#> 
#> $count
#> $count$a
#> [1] 3
#> 
#> $count$b
#> [1] 1
#> 
#> $count$c
#> [1] 1
#> 
#> $count$`<Missing>`
#> [1] 1
#> 
#> 
#> $count_fraction
#> $count_fraction$a
#> [1] 3.0 0.5
#> 
#> $count_fraction$b
#> [1] 1.0000000 0.1666667
#> 
#> $count_fraction$c
#> [1] 1.0000000 0.1666667
#> 
#> $count_fraction$`<Missing>`
#> [1] 1.0000000 0.1666667
#> 
#> 
#> $n_blq
#> [1] 0
#> 
#> $pval
#> [1] 0.005768471
#> 

# `s_compare.logical`

## Basic usage:
x <- c(TRUE, FALSE, TRUE, TRUE)
y <- c(FALSE, FALSE, TRUE)
s_compare(x, .ref_group = y, .in_ref_col = FALSE)
#> $n
#> [1] 4
#> 
#> $count
#> [1] 3
#> 
#> $count_fraction
#> [1] 3.00 0.75
#> 
#> $n_blq
#> [1] 0
#> 
#> $pval
#> [1] 0.2702894
#> 

## Management of NA values.
x <- c(NA, TRUE, FALSE)
y <- c(NA, NA, NA, NA, FALSE)
s_compare(x, .ref_group = y, .in_ref_col = FALSE, na.rm = TRUE)
#> $n
#> [1] 2
#> 
#> $count
#> [1] 1
#> 
#> $count_fraction
#> [1] 1.0 0.5
#> 
#> $n_blq
#> [1] 0
#> 
#> $pval
#> [1] 0.3864762
#> 
s_compare(x, .ref_group = y, .in_ref_col = FALSE, na.rm = FALSE)
#> $n
#> [1] 3
#> 
#> $count
#> [1] 1
#> 
#> $count_fraction
#> [1] 1.0000000 0.3333333
#> 
#> $n_blq
#> [1] 0
#> 
#> $pval
#> [1] 0.1675463
#> 

# `a_compare.numeric`
a_compare(
  rnorm(10, 5, 1),
  .ref_group = rnorm(20, -5, 1),
  .in_ref_col = FALSE,
  .var = "bla"
)
#> RowsVerticalSection (in_rows) object print method:
#> ----------------------------
#>        row_name                     formatted_cell indent_mod
#> 1             n                                 10          0
#> 2           sum                               57.7          0
#> 3          mean                                5.8          0
#> 4            sd                                0.7          0
#> 5            se                                0.2          0
#> 6       mean_sd                          5.8 (0.7)          0
#> 7       mean_se                          5.8 (0.2)          0
#> 8       mean_ci                       (5.26, 6.27)          0
#> 9      mean_sei                       (5.54, 5.99)          0
#> 10     mean_sdi                       (5.06, 6.47)          0
#> 11    mean_pval                               0.00          0
#> 12       median                                5.6          0
#> 13          mad                                0.0          0
#> 14    median_ci                       (5.19, 6.69)          0
#> 15    quantiles                          5.3 - 6.5          0
#> 16          iqr                                1.2          0
#> 17        range                          4.6 - 6.8          0
#> 18          min                                4.6          0
#> 19          max                                6.8          0
#> 20 median_range                    5.6 (4.6 - 6.8)          0
#> 21           cv                               12.2          0
#> 22    geom_mean                                5.7          0
#> 23 geom_mean_ci 5.24701151524491, 6.25291854529965          0
#> 24      geom_cv                               12.3          0
#> 25         pval                            <0.0001          0
#>                      row_label
#> 1                            n
#> 2                          Sum
#> 3                         Mean
#> 4                           SD
#> 5                           SE
#> 6                    Mean (SD)
#> 7                    Mean (SE)
#> 8                  Mean 95% CI
#> 9                Mean -/+ 1xSE
#> 10               Mean -/+ 1xSD
#> 11 Mean p-value (H0: mean = 0)
#> 12                      Median
#> 13   Median Absolute Deviation
#> 14               Median 95% CI
#> 15             25% and 75%-ile
#> 16                         IQR
#> 17                   Min - Max
#> 18                     Minimum
#> 19                     Maximum
#> 20          Median (Min - Max)
#> 21                      CV (%)
#> 22              Geometric Mean
#> 23       Geometric Mean 95% CI
#> 24         CV % Geometric Mean
#> 25            p-value (t-test)

# `a_compare.factor`
# We need to ungroup `count` and `count_fraction` first so that the `rtables` formatting
# functions can be applied correctly.
afun <- make_afun(
  getS3method("a_compare", "factor"),
  .ungroup_stats = c("count", "count_fraction")
)
x <- factor(c("a", "a", "b", "c", "a"))
y <- factor(c("a", "a", "b", "c"))
afun(x, .ref_group = y, .in_ref_col = FALSE)
#> RowsVerticalSection (in_rows) object print method:
#> ----------------------------
#>   row_name formatted_cell indent_mod                  row_label
#> 1        n              5          0                          n
#> 2        a              3          0                          a
#> 3        b              1          0                          b
#> 4        c              1          0                          c
#> 5        a        3 (60%)          0                          a
#> 6        b        1 (20%)          0                          b
#> 7        c        1 (20%)          0                          c
#> 8    n_blq              0          0                      n_blq
#> 9     pval         0.9560          0 p-value (chi-squared test)

# `a_compare.character`
afun <- make_afun(
  getS3method("a_compare", "character"),
  .ungroup_stats = c("count", "count_fraction")
)
x <- c("A", "B", "A", "C")
y <- c("B", "A", "C")
afun(x, .ref_group = y, .in_ref_col = FALSE, .var = "x", verbose = FALSE)
#> RowsVerticalSection (in_rows) object print method:
#> ----------------------------
#>   row_name formatted_cell indent_mod                  row_label
#> 1        n              4          0                          n
#> 2        A              2          0                          A
#> 3        B              1          0                          B
#> 4        C              1          0                          C
#> 5        A        2 (50%)          0                          A
#> 6        B        1 (25%)          0                          B
#> 7        C        1 (25%)          0                          C
#> 8    n_blq              0          0                      n_blq
#> 9     pval         0.9074          0 p-value (chi-squared test)

# `a_compare.logical`
afun <- make_afun(
  getS3method("a_compare", "logical")
)
x <- c(TRUE, FALSE, FALSE, TRUE, TRUE)
y <- c(TRUE, FALSE)
afun(x, .ref_group = y, .in_ref_col = FALSE)
#> RowsVerticalSection (in_rows) object print method:
#> ----------------------------
#>         row_name formatted_cell indent_mod                  row_label
#> 1              n              5          0                          n
#> 2          count              3          0                      count
#> 3 count_fraction        3 (60%)          0             count_fraction
#> 4          n_blq              0          0                      n_blq
#> 5           pval         0.8091          0 p-value (chi-squared test)

# `compare_vars()` in `rtables` pipelines

## Default output within a `rtables` pipeline.
lyt <- basic_table() %>%
  split_cols_by("ARMCD", ref_group = "ARM B") %>%
  compare_vars(c("AGE", "SEX"))
build_table(lyt, tern_ex_adsl)
#>                                  ARM B        ARM A        ARM C   
#> ———————————————————————————————————————————————————————————————————
#> AGE                                                                
#>   n                                73           69           58    
#>   Mean (SD)                    35.8 (7.1)   34.1 (6.8)   36.1 (7.4)
#>   p-value (t-test)                            0.1446       0.8212  
#> SEX                                                                
#>   n                                73           69           58    
#>   F                            40 (54.8%)   38 (55.1%)   32 (55.2%)
#>   M                            33 (45.2%)   31 (44.9%)   26 (44.8%)
#>   p-value (chi-squared test)                  1.0000       1.0000  

## Select and format statistics output.
lyt <- basic_table() %>%
  split_cols_by("ARMCD", ref_group = "ARM C") %>%
  compare_vars(
    vars = "AGE",
    .stats = c("mean_sd", "pval"),
    .formats = c(mean_sd = "xx.x, xx.x"),
    .labels = c(mean_sd = "Mean, SD")
  )
build_table(lyt, df = tern_ex_adsl)
#>                      ARM C       ARM A       ARM B  
#> ————————————————————————————————————————————————————
#> Mean, SD           36.1, 7.4   34.1, 6.8   35.8, 7.1
#> p-value (t-test)                0.1176      0.8212