Skip to contents

Suppose you need to create the table below, and need an ARD representation of the results to get started. Here, we will review an examples for creating a basic demographics table.

To get started, load the {cards} package.

Demographics

Characteristic Placebo
N = 86
Xanomeline Low Dose
N = 84
Xanomeline High Dose
N = 84
Age


    Median (Q1, Q3) 76 (69, 82) 78 (71, 82) 76 (71, 80)
    Mean (SD) 75 (9) 76 (8) 74 (8)
    Min - Max 52 - 89 51 - 88 56 - 88
Age Group, n (%)


    <65 14 (16.3%) 8 ( 9.5%) 11 (13.1%)
    65-80 42 (48.8%) 47 (56.0%) 55 (65.5%)
    >80 30 (34.9%) 29 (34.5%) 18 (21.4%)
Female, n (%) 53 (61.6%) 50 (59.5%) 40 (47.6%)

The table above has three types of data summaries: a continuous variable summary for AGE, a categorical variable summary for AGEGR1, and a dichotomous variable summary for SEX.

Continuous Summaries

To get a continuous variable summary, we will use the ard_continuous() function from the {cards} package.

df_continuous_ard <-
  ard_continuous(
    ADSL,
    by = ARM,
    variables = AGE,
    statistic = ~ continuous_summary_fns(c("median", "p25", "p75", "mean", "sd", "min", "max"))
  )
df_continuous_ard |> head(5)
#> {cards} data frame: 5 x 10
#>   group1 group1_level variable stat_name stat_label   stat
#> 1    ARM      Placebo      AGE    median     Median     76
#> 2    ARM      Placebo      AGE       p25         Q1     69
#> 3    ARM      Placebo      AGE       p75         Q3     82
#> 4    ARM      Placebo      AGE      mean       Mean 75.209
#> 5    ARM      Placebo      AGE        sd         SD   8.59
#>  4 more variables: context, fmt_fn, warning, error

Categorical Summaries

To get the categorical variable summary, we will use the ard_categorical() function.

df_categorical_ard <-
  ard_categorical(
    ADSL,
    by = ARM,
    variables = AGEGR1
  )
df_categorical_ard |> head(5)
#> {cards} data frame: 5 x 11
#>   group1 group1_level variable variable_level stat_name stat_label  stat
#> 1    ARM      Placebo   AGEGR1            <65         n          n    14
#> 2    ARM      Placebo   AGEGR1            <65         N          N    86
#> 3    ARM      Placebo   AGEGR1            <65         p          % 0.163
#> 4    ARM      Placebo   AGEGR1            >80         n          n    30
#> 5    ARM      Placebo   AGEGR1            >80         N          N    86
#>  4 more variables: context, fmt_fn, warning, error

Dichotomous Summaries

To get the dichotomous variable summary, we will use ard_dichotomous(). In this case, we want to show the Female ("F") level of the SEX variable and specify this with the values argument.

df_dichotomous_ard <-
  ard_dichotomous(
    ADSL,
    by = ARM,
    variables = SEX,
    value = list(SEX = "F")
  )
df_dichotomous_ard |> head(5)
#> {cards} data frame: 5 x 11
#>   group1 group1_level variable variable_level stat_name stat_label  stat
#> 1    ARM      Placebo      SEX              F         n          n    53
#> 2    ARM      Placebo      SEX              F         N          N    86
#> 3    ARM      Placebo      SEX              F         p          % 0.616
#> 4    ARM    Xanomeli…      SEX              F         n          n    40
#> 5    ARM    Xanomeli…      SEX              F         N          N    84
#>  4 more variables: context, fmt_fn, warning, error

Combine Results

As a last step, you can combine all of these objects into a single object using bind_ard(), which is similar to dplyr::bind_rows() and includes additional structural checks for our results.

bind_ard(
  df_continuous_ard,
  df_categorical_ard,
  df_dichotomous_ard
)
#> {cards} data frame: 57 x 11
#>    group1 group1_level variable variable_level stat_name stat_label   stat
#> 1     ARM      Placebo      AGE                   median     Median     76
#> 2     ARM      Placebo      AGE                      p25         Q1     69
#> 3     ARM      Placebo      AGE                      p75         Q3     82
#> 4     ARM      Placebo      AGE                     mean       Mean 75.209
#> 5     ARM      Placebo      AGE                       sd         SD   8.59
#> 6     ARM      Placebo      AGE                      min        Min     52
#> 7     ARM      Placebo      AGE                      max        Max     89
#> 8     ARM    Xanomeli…      AGE                   median     Median     76
#> 9     ARM    Xanomeli…      AGE                      p25         Q1   70.5
#> 10    ARM    Xanomeli…      AGE                      p75         Q3     80
#>  47 more rows
#>  Use `print(n = ...)` to see more rows
#>  4 more variables: context, fmt_fn, warning, error

Shortcut

The ard_stack() function provides a shortcut to perform the calculations above in a single step.

In the example below, the data and .by arguments are passed to each subsequent ard_*() function call. Moreover, this will also return the univariate tabulation of the .by variable, which would be used to add counts to the header row of the table.

ard_stack(
  data = ADSL,
  .by = ARM,
  ard_continuous(
    variables = AGE,
    statistic = ~ continuous_summary_fns(c("median", "p25", "p75", "mean", "sd", "min", "max"))
  ),
  ard_categorical(variables = AGEGR1),
  ard_dichotomous(variables = SEX, value = list(SEX = "F"))
)
#> {cards} data frame: 66 x 11
#>    group1 group1_level variable variable_level stat_name stat_label   stat
#> 1     ARM      Placebo      AGE                   median     Median     76
#> 2     ARM      Placebo      AGE                      p25         Q1     69
#> 3     ARM      Placebo      AGE                      p75         Q3     82
#> 4     ARM      Placebo      AGE                     mean       Mean 75.209
#> 5     ARM      Placebo      AGE                       sd         SD   8.59
#> 6     ARM      Placebo      AGE                      min        Min     52
#> 7     ARM      Placebo      AGE                      max        Max     89
#> 8     ARM      Placebo   AGEGR1            <65         n          n     14
#> 9     ARM      Placebo   AGEGR1            <65         N          N     86
#> 10    ARM      Placebo   AGEGR1            <65         p          %  0.163
#>  56 more rows
#>  Use `print(n = ...)` to see more rows
#>  4 more variables: context, fmt_fn, warning, error

Adverse Events

Next, we will review several examples for creating basic adverse events (AE) tables. We will skip to examples utilizing the shortcut functions ard_stack_hierarchical() and ard_stack_hierarchical_count(). These functions utilize multiple calls to ard_hierarchical() and ard_hierarchical_count() to calculate the needed summary statistics.

For the computations below, we will not only make use of a subset of the ADAE dataset. We will also rely on ADSL for the full study population, which is used as the denominator in the rate calculations.

To match the treatment arm variables, we need to do a small data manipulation on the naming of the treatment variable.

# rename trt variable
adsl <- ADSL |>
  dplyr::rename(TRTA = TRT01A)

# subset to Treatment emergent AES
adae <- ADAE |>
  # keep the most reported AEs for a smaller table
  dplyr::filter(.by = AETERM, dplyr::n() > 25, TRTEMFL == "Y")

Participant-level summaries

A common type of AE table contains participant-level summaries. Here, we are reporting the number and percentage of subjects with at least one AE by system organ class and preferred term.

Body System or Organ Class
    Dictionary-Derived Term
Placebo
N = 86
1
Xanomeline High Dose
N = 84
1
Xanomeline Low Dose
N = 84
1
Any Adverse Event 30 (34.9%) 59 (70.2%) 63 (75.0%)
GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS 15 (17.4%) 31 (36.9%) 34 (40.5%)
    APPLICATION SITE DERMATITIS 5 ( 5.8%) 7 ( 8.3%) 9 (10.7%)
    APPLICATION SITE ERYTHEMA 3 ( 3.5%) 15 (17.9%) 12 (14.3%)
    APPLICATION SITE IRRITATION 3 ( 3.5%) 9 (10.7%) 9 (10.7%)
    APPLICATION SITE PRURITUS 6 ( 7.0%) 22 (26.2%) 22 (26.2%)
NERVOUS SYSTEM DISORDERS 2 ( 2.3%) 11 (13.1%) 8 ( 9.5%)
    DIZZINESS 2 ( 2.3%) 11 (13.1%) 8 ( 9.5%)
SKIN AND SUBCUTANEOUS TISSUE DISORDERS 16 (18.6%) 30 (35.7%) 29 (34.5%)
    ERYTHEMA 8 ( 9.3%) 14 (16.7%) 14 (16.7%)
    PRURITUS 8 ( 9.3%) 26 (31.0%) 21 (25.0%)
    RASH 5 ( 5.8%) 9 (10.7%) 13 (15.5%)
1 n (%)

The ard_stack_hierarchical() function provides a shortcut to perform the calculations needed for the summary table in a single step.

In the example below, the data and by arguments are passed to each subsequent calculation. The function utilizes USUBJID (passed to the id argument) as the subject identifier for participant-level calculations, and ADSL is used to define the denominator. With variables = c(AEBODSYS, AEDECOD), the function returns rates of adverse events by AEDECOD nested within AESOC as well as by AESOC. With over_variables = TRUE, the function also returns rates of any adverse event across all system organ classes and preferred terms.

ard_stack_hierarchical(
  data = adae,
  by = TRTA,
  variables = c(AEBODSYS, AEDECOD),
  denominator = adsl,
  id = USUBJID,
  over_variables = TRUE
)
#> {cards} data frame: 117 x 13
#>    group1 group1_level group2 group2_level                     variable
#> 1    TRTA      Placebo   <NA>                                  AEBODSYS
#> 2    TRTA      Placebo   <NA>                                  AEBODSYS
#> 3    TRTA      Placebo   <NA>                                  AEBODSYS
#> 4    TRTA      Placebo   <NA>                                  AEBODSYS
#> 5    TRTA      Placebo   <NA>                                  AEBODSYS
#> 6    TRTA      Placebo   <NA>                                  AEBODSYS
#> 7    TRTA      Placebo   <NA>                                  AEBODSYS
#> 8    TRTA      Placebo   <NA>                                  AEBODSYS
#> 9    TRTA      Placebo   <NA>                                  AEBODSYS
#> 10   TRTA      Placebo   <NA>              ..ard_hierarchical_overall..
#>    variable_level stat_name stat_label  stat
#> 1       GENERAL …         n          n    15
#> 2       GENERAL …         N          N    86
#> 3       GENERAL …         p          % 0.174
#> 4       NERVOUS …         n          n     2
#> 5       NERVOUS …         N          N    86
#> 6       NERVOUS …         p          % 0.023
#> 7       SKIN AND…         n          n    16
#> 8       SKIN AND…         N          N    86
#> 9       SKIN AND…         p          % 0.186
#> 10           TRUE         n          n    30
#>  107 more rows
#>  Use `print(n = ...)` to see more rows
#>  4 more variables: context, fmt_fn, warning, error

Event-level Summaries

In addition to participant-level summaries, event-level summaries are often needed. For these types of tables, we report total counts of AEs , and therefore we can use the ADAE data directly. We will need to count AEs overall, by system organ class, and by preferred term (within system organ class).

Body System or Organ Class
    Dictionary-Derived Term
Placebo
N = 86
1
Xanomeline High Dose
N = 84
1
Xanomeline Low Dose
N = 84
1
Total Number of Adverse Events 64 176 169
GENERAL DISORDERS AND ADMINISTRATION SITE CONDITIONS 29 86 85
    APPLICATION SITE DERMATITIS 9 12 15
    APPLICATION SITE ERYTHEMA 3 23 20
    APPLICATION SITE IRRITATION 7 16 18
    APPLICATION SITE PRURITUS 10 35 32
NERVOUS SYSTEM DISORDERS 3 15 13
    DIZZINESS 3 15 13
SKIN AND SUBCUTANEOUS TISSUE DISORDERS 32 75 71
    ERYTHEMA 12 22 22
    PRURITUS 11 38 31
    RASH 9 15 18
1 n

The ard_stack_hierarchical_count() function provides a shortcut to perform the calculations needed for the summary table in a single step.

In the example below, the data and by arguments are passed to each subsequent calculation. With variables = c(AEBODSYS, AEDECOD), the function returns counts of adverse events by AEDECOD nested within AESOC as well as by AESOC. With over_variables = TRUE, the function also returns counts of any adverse event across all system organ classes and preferred terms.

ard_stack_hierarchical_count(
  data = adae,
  by = TRTA,
  variables = c(AEBODSYS, AETERM),
  over_variables = TRUE
)
#> {cards} data frame: 36 x 13
#>    group1 group1_level   group2 group2_level                     variable
#> 1    TRTA      Placebo     <NA>                                  AEBODSYS
#> 2    TRTA      Placebo     <NA>                                  AEBODSYS
#> 3    TRTA      Placebo     <NA>                                  AEBODSYS
#> 4    TRTA      Placebo     <NA>              ..ard_hierarchical_overall..
#> 5    TRTA      Placebo AEBODSYS    GENERAL …                       AETERM
#> 6    TRTA      Placebo AEBODSYS    GENERAL …                       AETERM
#> 7    TRTA      Placebo AEBODSYS    GENERAL …                       AETERM
#> 8    TRTA      Placebo AEBODSYS    GENERAL …                       AETERM
#> 9    TRTA      Placebo AEBODSYS    NERVOUS …                       AETERM
#> 10   TRTA      Placebo AEBODSYS    SKIN AND…                       AETERM
#>    variable_level stat_name stat_label stat
#> 1       GENERAL …         n          n   29
#> 2       NERVOUS …         n          n    3
#> 3       SKIN AND…         n          n   32
#> 4            TRUE         n          n   64
#> 5       APPLICAT…         n          n    9
#> 6       APPLICAT…         n          n    3
#> 7       APPLICAT…         n          n    7
#> 8       APPLICAT…         n          n   10
#> 9       DIZZINESS         n          n    3
#> 10       ERYTHEMA         n          n   12
#>  26 more rows
#>  Use `print(n = ...)` to see more rows
#>  4 more variables: context, fmt_fn, warning, error