library(haven) # Read SAS data
library(dplyr) # Manipulate data
library(tidyr) # Manipulate data
library(r2rtf) # Reporting in RTF format
7 AE summary
Following ICH E3 guidance, we summarize number of participants that were included in each safety analysis in Section 12.2, Adverse Events (AEs).
In this chapter, we illustrate how to summarize AEs information for a study.
The data used to summarize AE information is in adsl
and adae
datasets.
<- read_sas("data-adam/adsl.sas7bdat")
adsl <- read_sas("data-adam/adae.sas7bdat") adae
We first summarize participants in population by treatment arm.
<- adsl %>%
pop filter(SAFFL == "Y") %>%
rename(TRTAN = TRT01AN) %>%
count(TRTAN, name = "tot")
pop#> # A tibble: 3 × 2
#> TRTAN tot
#> <dbl> <int>
#> 1 0 86
#> 2 54 84
#> 3 81 84
We transform the data to simplify the analysis of each required AE criteria of interest.
- With one or more adverse events
- With drug-related adverse events
- With serious adverse events
- With serious drug-related adverse events
- Who died
<- adae %>%
tidy_ae mutate(
all = SAFFL == "Y",
drug = AEREL %in% c("POSSIBLE", "PROBABLE"),
ser = AESER == "Y",
drug_ser = drug & ser,
die = AEOUT == "FATAL"
%>%
) select(USUBJID, TRTAN, all, drug, ser, drug_ser, die) %>%
pivot_longer(cols = c(all, drug, ser, drug_ser, die))
%>% head(4)
tidy_ae #> # A tibble: 4 × 4
#> USUBJID TRTAN name value
#> <chr> <dbl> <chr> <lgl>
#> 1 01-701-1015 0 all TRUE
#> 2 01-701-1015 0 drug TRUE
#> 3 01-701-1015 0 ser FALSE
#> 4 01-701-1015 0 drug_ser FALSE
We summarize the number and percentage of participants who meet each AE criteria.
<- function(x, digits, width = digits + 4) {
fmt_num formatC(
x,digits = digits,
format = "f",
width = width
) }
<- tidy_ae %>%
ana filter(value == TRUE) %>%
group_by(TRTAN, name) %>%
summarise(n = n_distinct(USUBJID)) %>%
left_join(pop, by = "TRTAN") %>%
mutate(
pct = fmt_num(n / tot * 100, digits = 1),
n = fmt_num(n, digits = 0),
pct = paste0("(", pct, ")")
)
%>% head(4)
ana #> # A tibble: 4 × 5
#> # Groups: TRTAN [2]
#> TRTAN name n tot pct
#> <dbl> <chr> <chr> <int> <chr>
#> 1 0 all " 69" 86 ( 80.2)
#> 2 0 die " 2" 86 ( 2.3)
#> 3 0 drug " 44" 86 ( 51.2)
#> 4 54 all " 77" 84 ( 91.7)
We prepare reporting-ready dataset for each AE group.
<- ana %>%
t_ae pivot_wider(
id_cols = "name",
names_from = TRTAN,
values_from = c(n, pct),
values_fill = list(
n = " 0",
pct = "( 0.0)"
)
)
<- t_ae %>%
t_ae mutate(name = factor(
name,c("all", "drug", "ser", "drug_ser", "die"),
c(
"With one or more adverse events",
"With drug-related adverse events",
"With serious adverse events",
"With serious drug-related adverse events",
"Who died"
)%>%
)) arrange(name)
We prepare reporting-ready dataset for the analysis population.
<- pop %>%
t_pop mutate(
name = "Participants in population",
tot = fmt_num(tot, digits = 0)
%>%
) pivot_wider(
id_cols = name,
names_from = TRTAN,
names_prefix = "n_",
values_from = tot
)
t_pop#> # A tibble: 1 × 4
#> name n_0 n_54 n_81
#> <chr> <chr> <chr> <chr>
#> 1 Participants in population " 86" " 84" " 84"
The final report data is saved in tbl_ae_summary
.
<- bind_rows(t_pop, t_ae) %>%
tbl_ae_summary select(name, ends_with("_0"), ends_with("_54"), ends_with("_81"))
tbl_ae_summary#> # A tibble: 6 × 7
#> name n_0 pct_0 n_54 pct_54 n_81 pct_81
#> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
#> 1 Participants in population " 8… <NA> " 8… <NA> " 8… <NA>
#> 2 With one or more adverse events " 6… ( 80… " 7… ( 91.… " 7… ( 94.…
#> 3 With drug-related adverse events " 4… ( 51… " 7… ( 86.… " 7… ( 83.…
#> 4 With serious adverse events " … ( 0… " … ( 1.… " … ( 2.…
#> 5 With serious drug-related adverse events " … ( 0… " … ( 1.… " … ( 1.…
#> 6 Who died " … ( 2… " … ( 1.… " … ( 0.…
We define the format of the output using code below:
%>%
tbl_ae_summary rtf_title(
"Analysis of Adverse Event Summary",
"(Safety Analysis Population)"
%>%
) rtf_colheader(" | Placebo | Xanomeline Low Dose| Xanomeline High Dose",
col_rel_width = c(3.5, rep(2, 3))
%>%
) rtf_colheader(" | n | (%) | n | (%) | n | (%)",
col_rel_width = c(3.5, rep(c(0.7, 1.3), 3)),
border_top = c("", rep("single", 6)),
border_left = c("single", rep(c("single", ""), 3))
%>%
) rtf_body(
col_rel_width = c(3.5, rep(c(0.7, 1.3), 3)),
text_justification = c("l", rep("c", 6)),
border_left = c("single", rep(c("single", ""), 3))
%>%
) rtf_footnote("Every subject is counted a single time for each applicable row and column.") %>%
rtf_encode() %>%
write_rtf("tlf/tlf_ae_summary.rtf")
The procedure to generate an AE summary table can be summarized as follows:
- Step 1: Read data (i.e.,
adae
andadsl
) into R. - Step 2: Summarize participants in population by treatment arm, and name the dataset as
t_pop
. - Step 3: Summarize participants in population by required AE criteria of interest, and name the dataset as
t_ae
. - Step 4: Row-wise combine
t_pop
andt_ae
and format it by using r2rtf.