# load libraries
library(cards)
AET02 - Adverse Events
Adverse Events (AET02) QC Workflow
1. Generate a table using {chevron}
Show the code
<- chevron::aet02_main(chevron::syn_data, arm_var = "ARM", lbl_overall = "Overall ARM")
tlg_aet02 head(tlg_aet02, n = 15)
A: Drug X B: Placebo C: Combination Overall ARM
(N=15) (N=15) (N=15) (N=45)
———————————————————————————————————————————————————————————————————————————————————————————————————————————————————
Total number of patients with at least one adverse event 13 (86.7%) 14 (93.3%) 15 (100%) 42 (93.3%)
Overall total number of events 58 59 99 216
cl A.1
Total number of patients with at least one adverse event 7 (46.7%) 6 (40.0%) 10 (66.7%) 23 (51.1%)
Total number of events 8 11 16 35
dcd A.1.1.1.1 3 (20.0%) 1 (6.7%) 6 (40.0%) 10 (22.2%)
dcd A.1.1.1.2 5 (33.3%) 6 (40.0%) 6 (40.0%) 17 (37.8%)
cl B.1
Total number of patients with at least one adverse event 5 (33.3%) 6 (40.0%) 8 (53.3%) 19 (42.2%)
Total number of events 6 6 12 24
dcd B.1.1.1.1 5 (33.3%) 6 (40.0%) 8 (53.3%) 19 (42.2%)
cl B.2
Total number of patients with at least one adverse event 11 (73.3%) 8 (53.3%) 10 (66.7%) 29 (64.4%)
Total number of events 18 15 20 53
dcd B.2.1.2.1 5 (33.3%) 6 (40.0%) 5 (33.3%) 16 (35.6%)
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} package. Setting the add_tbl_str_decimals
to FALSE
will not return a column with the statistic as a formatted string. We also include a step to remove the “label” attribute for the statistics. The diffdf()
function is sensitive to attribute mismatch, so we will remove them (set to NULL
) to match the ARD results exactly.
<- rtables::as_result_df(tlg_aet02, make_ard = TRUE, add_tbl_str_decimals = FALSE)
rtables_result attr(rtables_result$stat, "label") <- NULL
1:6, c("group2", "group2_level", "variable", "variable_level", "stat")] rtables_result[
group2 | group2_level | variable | variable_level | stat |
---|---|---|---|---|
ARM | A: Drug X | USUBJID | unique | 13.0000000 |
ARM | A: Drug X | USUBJID | unique | 0.8666667 |
ARM | A: Drug X | USUBJID | nonunique | 58.0000000 |
ARM | A: Drug X | AEBODSYS | unique | 7.0000000 |
ARM | A: Drug X | AEBODSYS | unique | 0.4666667 |
ARM | A: Drug X | AEBODSYS | nonunique | 8.0000000 |
3. Create a comparable ARD
In the code below, we perform different data pre-processing for the different ARDs we want to create. Then, we generate separate ARDs using the {cards} package for the different sections of the AET02 table and compare them as subsets. Note: If your table does not have an “overall” column, you can use the ARD creation steps at the bottom of the page using primarily ard_categorical()
. ard_hierarchical()
is useful here to calculate the statistics for the overall column and allows for better filtering using the “context” column.
# data pre-processing. filter observations with ANL01FL = "Y"
<- chevron::syn_data$adae |>
adae ::filter(ANL01FL == "Y")
dplyr<- chevron::syn_data$adsl |>
adsl ::filter(ANL01FL == "Y")
dplyr
# ----- ARDS -----
<- ard_stack_hierarchical(
ard_result data = adae,
variables = c(ANL01FL, AEBODSYS, AEDECOD),
by = c(ARM),
denominator = adsl,
overall = TRUE,
id = USUBJID,
statistic = ~ c("n", "p")
|>
) apply_fmt_fn() |>
unlist_ard_columns() |>
::filter(context == "hierarchical")
dplyr
<-
ard_count_result ard_stack_hierarchical_count(
data = adae,
variables = c(ANL01FL, AEBODSYS),
by = ARM,
overall = TRUE,
denominator = ADSL
|>
) apply_fmt_fn() |>
unlist_ard_columns() |>
::filter(context == "hierarchical_count") dplyr
4. Statistics Comparison
We’ll modify the rtables result to closely match the ARD result:
- Rename “group2_level” to “ARM” to match the ARD.
- Remove any columns that aren’t in the ARD result (stat_name is being removed as it is a blank column)
<- rtables_result |>
rtables_result ::rename(
dplyrgroup1_level = group2_level,
group1 = group2,
group2 = group1,
group2_level = group1_level
)
head(rtables_result, n = 10)
group2 | group2_level | group1 | group1_level | variable | variable_level | variable_label | stat_name | stat |
---|---|---|---|---|---|---|---|---|
NA | NA | ARM | A: Drug X | USUBJID | unique | Total number of patients with at least one adverse event | NA | 13.0000000 |
NA | NA | ARM | A: Drug X | USUBJID | unique | Total number of patients with at least one adverse event | NA | 0.8666667 |
NA | NA | ARM | A: Drug X | USUBJID | nonunique | Overall total number of events | NA | 58.0000000 |
AEBODSYS | cl A.1 | ARM | A: Drug X | AEBODSYS | unique | Total number of patients with at least one adverse event | NA | 7.0000000 |
AEBODSYS | cl A.1 | ARM | A: Drug X | AEBODSYS | unique | Total number of patients with at least one adverse event | NA | 0.4666667 |
AEBODSYS | cl A.1 | ARM | A: Drug X | AEBODSYS | nonunique | Total number of events | NA | 8.0000000 |
AEBODSYS | cl A.1 | ARM | A: Drug X | AEDECOD | dcd A.1.1.1.1 | dcd A.1.1.1.1 | NA | 3.0000000 |
AEBODSYS | cl A.1 | ARM | A: Drug X | AEDECOD | dcd A.1.1.1.1 | dcd A.1.1.1.1 | NA | 0.2000000 |
AEBODSYS | cl A.1 | ARM | A: Drug X | AEDECOD | dcd A.1.1.1.2 | dcd A.1.1.1.2 | NA | 5.0000000 |
AEBODSYS | cl A.1 | ARM | A: Drug X | AEDECOD | dcd A.1.1.1.2 | dcd A.1.1.1.2 | NA | 0.3333333 |
We can compare the data in subsets to minimize reformatting steps
# subgroup analysis
<- rtables_result |>
rtables_result_sub1 ::filter(variable == "AEDECOD") |>
dplyr::select(c("group1", "group1_level", "variable", "variable_level", "stat"))
dplyr
<- ard_result |>
ard_sub1 ::filter(variable == "AEDECOD") |>
dplyr::mutate(
dplyrgroup1 = dplyr::case_when(
== "ANL01FL" ~ "ARM",
group1 TRUE ~ group1
),group1_level = dplyr::case_when(
== "Y" ~ "Overall ARM",
group1_level TRUE ~ group1_level
)|>
) ::select(c("group1", "group1_level", "variable", "variable_level", "stat"))
dplyr
::diffdf(rtables_result_sub1, ard_sub1, keys = c("group1", "group1_level", "variable", "variable_level", "stat")) diffdf
No issues were found!
Compare the second subset
<- rtables_result |>
rtables_result_sub2 ::filter(variable %in% c("USUBJID", "AEBODSYS") & variable_level != "nonunique") |>
dplyr::select(c("group1", "group1_level", "group2", "group2_level", "stat")) |>
dplyr::rename(
dplyrvariable = group2,
variable_level = group2_level
|>
) ::mutate(
dplyrvariable = dplyr::coalesce(variable, "ANL01FL"),
variable_level = dplyr::coalesce(variable_level, "Y")
)
<- ard_result |>
ard_sub2 ::filter(variable %in% c("ANL01FL", "AEBODSYS")) |>
dplyr::mutate(
dplyrgroup1 = dplyr::recode(group1, "ANL01FL" = "ARM"),
group1_level = dplyr::recode(group1_level, "Y" = "Overall ARM"),
group1 = dplyr::coalesce(group1, "ARM"),
group1_level = dplyr::coalesce(group1_level, "Overall ARM")
|>
) ::select(c("group1", "group1_level", "variable", "variable_level", "stat"))
dplyr
::diffdf(rtables_result_sub2, ard_sub2, keys = c("group1", "group1_level", "variable", "variable_level", "stat")) diffdf
No issues were found!
Total Number of Events (ARD counts data.frame)
# reformat rtables
<- rtables_result |>
rtables_count ::filter(variable_label %in% c("Total number of events", "Overall total number of events")) |>
dplyr::mutate(
dplyrgroup2 = dplyr::case_when(
== "Overall total number of events" ~ "ANL01FL",
variable_label TRUE ~ group2
),group2_level = dplyr::case_when(
== "Overall total number of events" ~ "Y",
variable_label TRUE ~ group2_level
)|>
) ::select("group1", "group1_level", "group2", "group2_level", "stat")
dplyr
# reformat ARD result
<- ard_count_result |>
ard_count_result ::mutate(
dplyrgroup1 = dplyr::coalesce(group1, "ARM"),
group1_level = dplyr::coalesce(group1_level, "Overall ARM"),
group1 = dplyr::case_when(
== "ANL01FL" ~ "ARM",
group1 TRUE ~ group1
),group1_level = dplyr::case_when(
== "Y" ~ "Overall ARM",
group1_level TRUE ~ group1_level
)|>
) ::select("group1", "group1_level", "variable", "variable_level", "stat") |>
dplyr::rename(
dplyrgroup2 = variable,
group2_level = variable_level
)
::diffdf(rtables_count, ard_count_result, keys = c("group1", "group1_level", "group2", "group2_level", "stat")) diffdf
No issues were found!