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 = 861 |
Xanomeline High Dose N = 841 |
Xanomeline Low Dose N = 841 |
---|---|---|---|
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 = 861 |
Xanomeline High Dose N = 841 |
Xanomeline Low Dose N = 841 |
---|---|---|---|
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