cardinal
  • Home
  • Template Catalog
  • About
  • Resources
  • Help
    • Getting Started
    • Report a Bug
    • FAQ

FDA Table 18

Summary Assessment of [Insert AE of Interest], Safety Population, Pooled Analysis (or Trial X)

table
FDA
safety
adverse events
  • Table Preview
  • Setup
  • Build Table
  • Build ARD

Code
# Load libraries & data -------------------------------------
library(dplyr)
library(cards)
library(cardx)
library(gtsummary)

adsl <- random.cdisc.data::cadsl
adae <- random.cdisc.data::cadae

set.seed(1)
adae$AESIFL <- ifelse(adae$AESOC %in% c("cl A", "cl D"), "Y", "N")

# Pre-processing --------------------------------------------
adsl <- adsl |>
  filter(SAFFL == "Y") # safety population

data <- adae |>
  filter(
    SAFFL == "Y", # safety population
    AESIFL == "Y" # AESI assessment
  )

# dataset of AE flag variable counts by subject
data_ae_fl <-
  adsl |>
  select(USUBJID, TRT01A) |>
  # create subject-level flags from adae data
  left_join(
    data |>
      select(USUBJID, AESER, AESDTH, AESLIFE, AESHOSP, AESDISAB, AESCONG, AESMIE, AEACN) |>
      mutate(
        # Serious AE
        ae_ser = any(AESER == "Y"),
        # Serious AE leading to death
        ae_ser_death = any(AESER == "Y" & AESDTH == "Y"),
        ae_ser_life = any(AESER == "Y" & AESLIFE == "Y"),
        ae_ser_hosp = any(AESER == "Y" & AESHOSP == "Y"),
        ae_ser_disab = any(AESER == "Y" & AESDISAB == "Y"),
        ae_ser_cong = any(AESER == "Y" & AESCONG == "Y"),
        ae_ser_oth = any(AESER == "Y" & AESMIE == "Y"),
        # AE resulting in discontinuation
        ae_withdraw = any(AEACN == "DRUG WITHDRAWN"),
        .by = USUBJID
      ),
    by = "USUBJID"
  ) |>
  distinct(USUBJID, .keep_all = TRUE) |>
  # add number of AEs
  left_join(
    data |> summarise(.by = USUBJID, ae_count = n()),
    by = "USUBJID",
    relationship = "one-to-one"
  )
Code
## AE grouping flags section --------
tbl_ae_gp <- data |>
  tbl_hierarchical(
    variables = AEDECOD,
    id = USUBJID,
    denominator = adsl,
    by = TRT01A,
    overall_row = TRUE,
    label = list(
      ..ard_hierarchical_overall.. = "[Insert AE of Interest]",
      AEDECOD = "AE of Interest Assessment"
    )
  ) |>
  modify_indent(columns = label, rows = variable != "..ard_hierarchical_overall..", indent = 4L)

## Maximum severity section ---------
tbl_ae_sev <- data |>
  ard_categorical_max(variables = AESEV, id = USUBJID, by = TRT01A, denominator = adsl, quiet = TRUE) |>
  tbl_ard_summary(by = TRT01A, label = list(AESEV = "Maximum severity"))
Warning: `ard_categorical_max()` was deprecated in cardx 0.3.0.
ℹ Please use `ard_tabulate_max()` instead.
Code
## Events section -------------------
tbl_ae_fl <- data_ae_fl |>
  tbl_summary(
    by = "TRT01A",
    include = c(ae_ser, ae_ser_death, ae_ser_life, ae_ser_hosp, ae_ser_disab, ae_ser_cong, ae_ser_oth, ae_withdraw),
    missing = "no",
    percent = adsl,
    label = list(
      ae_ser = "SAE",
      ae_ser_death = "Death",
      ae_ser_life = "Life-threatening",
      ae_ser_hosp = "Initial or prolonged hospitalization",
      ae_ser_disab = "Disability or permanent damage",
      ae_ser_cong = "Congenital anomaly or birth defect",
      ae_ser_oth = "Other",
      ae_withdraw = "Resulting in treatment discontinuation"
    )
  ) |>
  modify_indent(columns = label, rows = !variable %in% c("ae_ser", "ae_withdraw"), indent = 4L)

## Build table ----------------------
tbl <- tbl_stack(list(tbl_ae_gp, tbl_ae_sev, tbl_ae_fl), quiet = TRUE)

tbl

Code
ard <- gather_ard(tbl)
ard
[[1]]
[[1]]$tbl_hierarchical
{cards} data frame: 63 x 13
   group1 group1_level                     variable variable_level stat_name stat_label  stat stat_fmt
1    <NA>                                    TRT01A      A: Drug X         n          n   134      134
2    <NA>                                    TRT01A      A: Drug X         N          N   400      400
3    <NA>                                    TRT01A      A: Drug X         p          % 0.335     33.5
4    <NA>                                    TRT01A      B: Place…         n          n   134      134
5    <NA>                                    TRT01A      B: Place…         N          N   400      400
6    <NA>                                    TRT01A      B: Place…         p          % 0.335     33.5
7    <NA>                                    TRT01A      C: Combi…         n          n   132      132
8    <NA>                                    TRT01A      C: Combi…         N          N   400      400
9    <NA>                                    TRT01A      C: Combi…         p          %  0.33     33.0
10 TRT01A    A: Drug X ..ard_hierarchical_overall..           TRUE         n          n   107      107
ℹ 53 more rows
ℹ Use `print(n = ...)` to see more rows
ℹ 5 more variables: context, fmt_fun, warning, error, gts_column


[[2]]
[[2]]$tbl_ard_summary
{cards} data frame: 29 x 12
   group1 group1_level variable variable_level stat_name stat_label  stat
1  TRT01A    A: Drug X    AESEV           MILD         n          n    16
2  TRT01A    A: Drug X    AESEV           MILD         N          N   134
3  TRT01A    A: Drug X    AESEV           MILD         p          % 0.119
4  TRT01A    A: Drug X    AESEV       MODERATE         n          n    41
5  TRT01A    A: Drug X    AESEV       MODERATE         N          N   134
6  TRT01A    A: Drug X    AESEV       MODERATE         p          % 0.306
7  TRT01A    A: Drug X    AESEV         SEVERE         n          n    50
8  TRT01A    A: Drug X    AESEV         SEVERE         N          N   134
9  TRT01A    A: Drug X    AESEV         SEVERE         p          % 0.373
10 TRT01A    B: Place…    AESEV           MILD         n          n    19
ℹ 19 more rows
ℹ Use `print(n = ...)` to see more rows
ℹ 5 more variables: context, fmt_fun, warning, error, gts_column


[[3]]
[[3]]$tbl_summary
{cards} data frame: 221 x 12
   group1 group1_level     variable variable_level stat_name stat_label  stat
1  TRT01A    A: Drug X       ae_ser           TRUE         n          n    75
2  TRT01A    A: Drug X       ae_ser           TRUE         N          N   134
3  TRT01A    A: Drug X       ae_ser           TRUE         p          %  0.56
4  TRT01A    A: Drug X ae_ser_death           TRUE         n          n    50
5  TRT01A    A: Drug X ae_ser_death           TRUE         N          N   134
6  TRT01A    A: Drug X ae_ser_death           TRUE         p          % 0.373
7  TRT01A    A: Drug X  ae_ser_life           TRUE         n          n     5
8  TRT01A    A: Drug X  ae_ser_life           TRUE         N          N   134
9  TRT01A    A: Drug X  ae_ser_life           TRUE         p          % 0.037
10 TRT01A    A: Drug X  ae_ser_hosp           TRUE         n          n    11
ℹ 211 more rows
ℹ Use `print(n = ...)` to see more rows
ℹ 5 more variables: context, fmt_fun, warning, error, gts_column
Source Code
---
title: FDA Table 18
subtitle: Summary Assessment of [Insert AE of Interest], Safety Population, Pooled Analysis (or Trial X)
categories: [table, FDA, safety, adverse events]
---

::: panel-tabset
## Table Preview

```{r img, echo=FALSE, fig.align='center', out.width='45%'}
knitr::include_graphics("result.png")
```

## Setup

```{r setup, message=FALSE}
# Load libraries & data -------------------------------------
library(dplyr)
library(cards)
library(cardx)
library(gtsummary)

adsl <- random.cdisc.data::cadsl
adae <- random.cdisc.data::cadae

set.seed(1)
adae$AESIFL <- ifelse(adae$AESOC %in% c("cl A", "cl D"), "Y", "N")

# Pre-processing --------------------------------------------
adsl <- adsl |>
  filter(SAFFL == "Y") # safety population

data <- adae |>
  filter(
    SAFFL == "Y", # safety population
    AESIFL == "Y" # AESI assessment
  )

# dataset of AE flag variable counts by subject
data_ae_fl <-
  adsl |>
  select(USUBJID, TRT01A) |>
  # create subject-level flags from adae data
  left_join(
    data |>
      select(USUBJID, AESER, AESDTH, AESLIFE, AESHOSP, AESDISAB, AESCONG, AESMIE, AEACN) |>
      mutate(
        # Serious AE
        ae_ser = any(AESER == "Y"),
        # Serious AE leading to death
        ae_ser_death = any(AESER == "Y" & AESDTH == "Y"),
        ae_ser_life = any(AESER == "Y" & AESLIFE == "Y"),
        ae_ser_hosp = any(AESER == "Y" & AESHOSP == "Y"),
        ae_ser_disab = any(AESER == "Y" & AESDISAB == "Y"),
        ae_ser_cong = any(AESER == "Y" & AESCONG == "Y"),
        ae_ser_oth = any(AESER == "Y" & AESMIE == "Y"),
        # AE resulting in discontinuation
        ae_withdraw = any(AEACN == "DRUG WITHDRAWN"),
        .by = USUBJID
      ),
    by = "USUBJID"
  ) |>
  distinct(USUBJID, .keep_all = TRUE) |>
  # add number of AEs
  left_join(
    data |> summarise(.by = USUBJID, ae_count = n()),
    by = "USUBJID",
    relationship = "one-to-one"
  )
```

## Build Table

```{r tbl, results = 'hide'}
## AE grouping flags section --------
tbl_ae_gp <- data |>
  tbl_hierarchical(
    variables = AEDECOD,
    id = USUBJID,
    denominator = adsl,
    by = TRT01A,
    overall_row = TRUE,
    label = list(
      ..ard_hierarchical_overall.. = "[Insert AE of Interest]",
      AEDECOD = "AE of Interest Assessment"
    )
  ) |>
  modify_indent(columns = label, rows = variable != "..ard_hierarchical_overall..", indent = 4L)

## Maximum severity section ---------
tbl_ae_sev <- data |>
  ard_categorical_max(variables = AESEV, id = USUBJID, by = TRT01A, denominator = adsl, quiet = TRUE) |>
  tbl_ard_summary(by = TRT01A, label = list(AESEV = "Maximum severity"))

## Events section -------------------
tbl_ae_fl <- data_ae_fl |>
  tbl_summary(
    by = "TRT01A",
    include = c(ae_ser, ae_ser_death, ae_ser_life, ae_ser_hosp, ae_ser_disab, ae_ser_cong, ae_ser_oth, ae_withdraw),
    missing = "no",
    percent = adsl,
    label = list(
      ae_ser = "SAE",
      ae_ser_death = "Death",
      ae_ser_life = "Life-threatening",
      ae_ser_hosp = "Initial or prolonged hospitalization",
      ae_ser_disab = "Disability or permanent damage",
      ae_ser_cong = "Congenital anomaly or birth defect",
      ae_ser_oth = "Other",
      ae_withdraw = "Resulting in treatment discontinuation"
    )
  ) |>
  modify_indent(columns = label, rows = !variable %in% c("ae_ser", "ae_withdraw"), indent = 4L)

## Build table ----------------------
tbl <- tbl_stack(list(tbl_ae_gp, tbl_ae_sev, tbl_ae_fl), quiet = TRUE)

tbl
```

```{r eval=FALSE, include=FALSE}
gt::gtsave(as_gt(tbl), filename = "result.png")
```

```{r img, echo=FALSE, fig.align='center', out.width='45%'}
```

## Build ARD

```{r ard, message=FALSE, warning=FALSE, results='hide'}
ard <- gather_ard(tbl)
ard
```

```{r, echo=FALSE}
# Print ARD
withr::local_options(width = 9999)
print(ard)
```
:::
 
  • This website as well as code examples are licensed under the Apache License, Version 2.0.
Cookie Preferences