I want to count serious adverse events per subject per treatment arm, and display the occurrence for each preferred term (PT) within the corresponding system organ class (SOC). For this, I take the code proposed in the cardinal template catalog for creating safety tables.
However, it drops levels of SOC and PT which are 0 for all treatment arms. Is there a way to force displaying all factor levels in the table?
Compared to the code linked above, I tried to re-assign the factor levels in the data preprocessing step, but this has no effect. It still procudes the table as shown in the link, meaning it drops "empty" factor levels. I would love to produce the same table but having all factor levels displayed with "0" in all variables. This is the code I tried
# Load packages & data -------------------------------------
library(dplyr)
library(gtsummary)
adsl <- random.cdisc.data::cadsl
adae <- random.cdisc.data::cadae
# Capture factor levels
lev_soc <- levels(adae[["AESOC"]])
lev_decod <- levels(adae[["AEDECOD"]])
# Pre-processing --------------------------------------------
adae <- adae %>%
filter(
# only serious adverse events
AESER == "Y"
) %>%
# Re-assign factor levels
mutate(
AESOC = factor(AESOC, levels = lev_soc),
AEDECOD = factor(AEDECOD, levels = lev_decod)
)
# Generate table ---------------------------------------------
tbl <- adae |>
tbl_hierarchical(
variables = c(AESOC, AEDECOD),
by = ARM,
id = USUBJID,
denominator = adsl,
overall_row = TRUE,
label = "..ard_hierarchical_overall.." ~ "Any SAE"
)
tbl
The tbl_hierarchical() function, by design, removes unobserved combinations, as this is the typical need. But to get all combinations, we can merge the serious AEs table with a table containing all the AEs. After the merge, we'll have all combinations.
# Load packages & data -------------------------------------
library(dplyr, warn.conflicts = FALSE)
library(gtsummary)
adsl <- random.cdisc.data::cadsl
adae <- random.cdisc.data::cadae[1:5,]
# Pre-processing --------------------------------------------
adae_ser <- adae %>%
# only serious adverse events
filter(AESER == "Y")
# Generate table ---------------------------------------------
# build table of serious events
tbl_ser <- adae_ser |>
tbl_hierarchical(
variables = c(AESOC, AEDECOD),
by = ARM,
id = USUBJID,
denominator = adsl,
overall_row = TRUE,
label = "..ard_hierarchical_overall.." ~ "Any SAE"
)
# build table of all AEs
tbl_all <- adae |>
tbl_hierarchical(
variables = c(AESOC, AEDECOD),
id = USUBJID,
denominator = adsl,
overall_row = TRUE,
label = "..ard_hierarchical_overall.." ~ "Any SAE"
) |>
# hide statistics columns (since we do not need to see these results)
modify_column_hide(all_stat_cols())
# merge the tables
tbl_final <-
list(tbl_all, tbl_ser) |>
tbl_merge(tab_spanner = FALSE) |>
# the missing cells are the non-serious AEs, fill them with zeros
modify_missing_symbol(
symbol = "0 (0%)",
columns = all_stat_cols(),
rows = TRUE
)
Created on 2025-08-01 with reprex v2.1.1
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With