Skip to contents

Generic counter for AE-style tables: counts unique subjects at the class level, term level, and overall, optionally stratified by treatment and grade/severity. Works for adverse events, medical history, prior/ concomitant medications, or anything with a class/term hierarchy.

Usage

ae_summary(
  data,
  adsl,
  id_var = cctu_opt("subjid_string"),
  term_var,
  class_var = NULL,
  trt_var = NULL,
  overall = TRUE,
  grade_var = NULL,
  grades = NULL,
  grade_layout = c("vertical", "horizontal"),
  grade_count = c("worst", "any"),
  grade_report = c("all", "high"),
  grade_high = 3L,
  min_pct = 0,
  class_sort = c("freq", "alpha"),
  any_label = "Participants with any event"
)

Arguments

data

Event-level dataset (one row per event).

adsl

Subject-level dataset providing denominators.

id_var

Subject ID column name (string). Must exist in both `data` and `adsl`.

term_var

Preferred term column name in `data` (string).

class_var

Class/SOC column name in `data` (string), or `NULL`. When `NULL`, the table is flat: a top "any event" row followed by term-level rows, with no class grouping.

trt_var

Optional treatment column in both `adsl` and `data`.

overall

Add a Total column when `trt_var` is given.

grade_var

Optional grade/severity column in `data`.

grades

Grade levels to report; defaults to "Any grade" + observed. When supplied, the order is taken as ascending severity (worst last), which also drives worst-grade counting.

grade_layout

When `grade_var` is given, "vertical" (default) nests grades as rows beneath each term: the term row shows the any-grade count and one indented sub-row per grade group gives the subject count for that group. "horizontal" instead puts each grade group in its own column. Class/overall rows stay any-grade. No effect when `grade_var` is `NULL`.

grade_count

How a subject is counted across grades for a given term (or class). "worst" (default) counts each subject once, at their maximum grade, so grade rows are mutually exclusive and sum to the any-grade count. "any" counts a subject at every grade they experienced (rows may sum past the any-grade count). Worst-grade is taken independently at each level.

grade_report

Which grade groups to show. "all" (default) reports each grade. "high" reports a single collapsed "Grade >=k" group (k = `grade_high`) alongside the any-grade row. Requires numeric grade labels (e.g. "Grade 3", "3").

grade_high

Threshold k for `grade_report = "high"`; default 3 gives a "Grade >=3" group.

min_pct

Term-level frequency filter (percent); 0 disables.

class_sort

"freq" (default) or "alpha".

any_label

Label for the top "any event" row. Defaults to "Subjects with any event"; pass e.g. "Patients with any AE" or "Subjects with any medical history" to match context.

Value

A data.frame of class cttab: a label column, one column per arm (or arm x grade group), and a row_style attribute (via format_table) that bolds the any-event and class rows - and, in the vertical grade layout, the term rows that carry nested grade sub-rows - and indents the term / grade rows for write_table.

Examples

adsl <- data.frame(id = sprintf("S%02d", 1:10),
                   arm = rep(c("Active", "Placebo"), each = 5))
ae <- data.frame(
  id  = c("S01", "S01", "S02", "S03", "S06", "S07"),
  soc = c("Skin", "GI", "Skin", "Skin", "GI", "Skin"),
  pt  = c("Rash", "Nausea", "Rash", "Pruritus", "Nausea", "Rash"),
  gr  = c("Grade 1", "Grade 3", "Grade 2", "Grade 1", "Grade 2", "Grade 1")
)
# Class -> term hierarchy with worst-grade sub-rows and a Total column.
ae_summary(ae, adsl, id_var = "id", class_var = "soc", term_var = "pt",
           trt_var = "arm", grade_var = "gr")
#> ┌───────────────────────────┬────────┬────────┬────────┐
#> |                           │ Active │Placebo │ Total  |
#> ├───────────────────────────┴────────┴────────┴────────┤
#> |Participants with any event│3 (60.0)│2 (40.0)│5 (50.0)|
#> |Skin                       │3 (60.0)│1 (20.0)│4 (40.0)|
#> |     Rash                  │2 (40.0)│1 (20.0)│3 (30.0)|
#> |        Grade 1            │1 (20.0)│1 (20.0)│2 (20.0)|
#> |        Grade 2            │1 (20.0)│   0    │1 (10.0)|
#> |        Grade 3            │   0    │0 (0.0) │   0    |
#> |     Pruritus              │1 (20.0)│   0    │1 (10.0)|
#> |        Grade 1            │1 (20.0)│   0    │1 (10.0)|
#> |        Grade 3            │   0    │0 (0.0) │   0    |
#> |GI                         │1 (20.0)│1 (20.0)│2 (20.0)|
#> |     Nausea                │1 (20.0)│1 (20.0)│2 (20.0)|
#> |        Grade 2            │   0    │1 (20.0)│1 (10.0)|
#> |        Grade 3            │1 (20.0)│0 (0.0) │1 (10.0)|
#> └───────────────────────────┴────────┴────────┴────────┘

# Flat table (no class): a single bold any-event row over indented terms.
ae_summary(ae, adsl, id_var = "id", term_var = "pt", trt_var = "arm")
#> ┌───────────────────────────┬────────┬────────┬────────┐
#> |                           │ Active │Placebo │ Total  |
#> ├───────────────────────────┴────────┴────────┴────────┤
#> |Participants with any event│3 (60.0)│2 (40.0)│5 (50.0)|
#> |     Rash                  │2 (40.0)│1 (20.0)│3 (30.0)|
#> |     Nausea                │1 (20.0)│1 (20.0)│2 (20.0)|
#> |     Pruritus              │1 (20.0)│   0    │1 (10.0)|
#> └───────────────────────────┴────────┴────────┴────────┘