You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用gtsummary生成含唯一受试者计数的不良事件(AE)表格的技术问题

使用gtsummary生成含唯一受试者计数的不良事件(AE)表格的技术问题

看起来你在尝试用gtsummary构建非嵌套的AE汇总表,每个行对应独立的唯一受试者计数(比如任意TEAE、任意严重TEAE这类独立类别),但用tbl_hierarchical遇到了零计数行不显示、计数强制嵌套的问题——这很正常,毕竟tbl_hierarchical本来是为层级结构(比如系统器官分类下的具体AE)设计的,用来做独立类别汇总确实有点“错位”。下面我针对你的两个核心挑战给出具体的解决方案:

一、先解决「非嵌套独立计数」的问题

我们的核心目标是:每个AE类别都独立统计唯一受试者数,不受其他类别层级影响。这里更适合用tbl_summary配合数据预处理来实现,而非tbl_hierarchical:

步骤1:预处理数据,确保每个受试者只被计数一次

一个受试者可能有多个AE记录,但我们要的是唯一受试者数,所以先按受试者去重,保留每个受试者的各类AE标记:

# 按受试者+治疗组去重,生成每个受试者的各类AE状态(仅保留是否符合类别)
adae_subj <- adae %>%
  group_by(USUBJID, TRT01A, TRT01AN) %>%
  summarize(
    ANY.TEAE = if_else(any(ANY.TEAE == "Any TEAE"), "Any TEAE", "N"),
    ANY.SERAE = if_else(any(ANY.SERAE == "Any TE Serious AE"), "Any TE Serious AE", "N"),
    ANY.DREL = if_else(any(ANY.DREL == "Any Drug Related AE"), "Any Drug Related AE", "N"),
    ANY.SERREL = if_else(any(ANY.SERREL == "Any Drug Related Serious AE"), "Any Drug Related Serious AE", "N"),
    .groups = "drop"
  )

步骤2:宽转长,适配tbl_summary的分类统计逻辑

把每个AE类别转成单独的行,方便tbl_summary批量处理:

adae_long <- adae_subj %>%
  pivot_longer(
    cols = starts_with("ANY."),
    names_to = "ae_category",
    values_to = "ae_status"
  ) %>%
  filter(ae_status != "N")  # 先过滤掉无符合的标记,后续再处理零计数

步骤3:用tbl_summary生成独立计数表

关联adsl作为分母,指定按治疗组分组统计唯一受试者数:

# 先从adsl提取各组总受试者数,作为统计分母
trt_totals <- adsl %>%
  group_by(TRT01A) %>%
  summarize(total_n = n_distinct(USUBJID), .groups = "drop")

# 生成基础表格
ae_table <- adae_long %>%
  tbl_summary(
    by = TRT01A,
    include = ae_category,
    type = all_categorical() ~ "categorical",
    statistic = all_categorical() ~ "{n} ({p}%)",
    # 手动指定各组分母,确保用adsl的总受试者数
    denominator = list(
      "Xanomeline High Dose" = trt_totals$total_n[trt_totals$TRT01A == "Xanomeline High Dose"],
      "Xanomeline Low Dose" = trt_totals$total_n[trt_totals$TRT01A == "Xanomeline Low Dose"],
      "Placebo" = trt_totals$total_n[trt_totals$TRT01A == "Placebo"]
    )
  ) %>%
  add_overall(last = TRUE) %>%
  # 适配你需要的表头格式
  modify_header(
    all_stat_cols() ~ "**{level}**\n(N = {n})\nn(%)",
    stat_0 ~ "**Total**\n(N = {n})\nn(%)",
    label ~ "Number of Participants"
  ) %>%
  modify_column_hide(variable)  # 隐藏原始变量列,只保留AE类别

二、解决「显示零计数行」的问题

默认情况下,tbl_summary不会显示某组中计数为0的AE类别,我们需要先生成所有AE类别+治疗组的全组合,再填充零计数:

步骤1:生成AE类别与治疗组的全组合

# 提取所有需要统计的AE类别
ae_categories <- c("Any TEAE", "Any TE Serious AE", "Any Drug Related AE", "Any Drug Related Serious AE")
# 提取所有治疗组
trt_groups <- unique(adae_subj$TRT01A)

# 生成所有可能的组合,确保没有遗漏
full_combinations <- expand.grid(
  ae_category = ae_categories,
  TRT01A = trt_groups,
  stringsAsFactors = FALSE
)

步骤2:合并数据并填充零计数

adae_long_full <- adae_long %>%
  group_by(ae_category, TRT01A) %>%
  summarize(n = n_distinct(USUBJID), .groups = "drop") %>%
  # 关联全组合,补全零计数的行
  right_join(full_combinations, by = c("ae_category", "TRT01A")) %>%
  mutate(n = replace_na(n, 0)) %>%
  # 关联分母计算百分比
  left_join(trt_totals, by = "TRT01A") %>%
  mutate(ae_status = if_else(n > 0, ae_category, "N")) %>%
  ungroup()

步骤3:调整tbl_summary配置,显示零计数

ae_table_with_zero <- adae_long_full %>%
  tbl_summary(
    by = TRT01A,
    include = ae_category,
    type = all_categorical() ~ "categorical",
    statistic = all_categorical() ~ "{n} ({p}%)",
    denominator = list(
      "Xanomeline High Dose" = trt_totals$total_n[trt_totals$TRT01A == "Xanomeline High Dose"],
      "Xanomeline Low Dose" = trt_totals$total_n[trt_totals$TRT01A == "Xanomeline Low Dose"],
      "Placebo" = trt_totals$total_n[trt_totals$TRT01A == "Placebo"]
    ),
    missing = "always",
    missing_text = "0 (0.0%)"
  ) %>%
  add_overall(last = TRUE) %>%
  modify_header(
    all_stat_cols() ~ "**{level}**\n(N = {n})\nn(%)",
    stat_0 ~ "**Total**\n(N = {n})\nn(%)",
    label ~ "Number of Participants"
  ) %>%
  modify_column_hide(variable) %>%
  # 过滤掉自动生成的"Missing"行,只保留我们需要的AE类别行
  modify_filter(label %in% ae_categories) %>%
  # 移除默认表头脚注
  remove_footnote_header(columns = all_stat_cols())

三、额外格式对齐调整

如果你需要和原来用tbl_hierarchical生成的格式完全一致,还可以添加:

ae_table_with_zero <- ae_table_with_zero %>%
  # 调整缩进(非嵌套所以设为0)
  modify_indent(
    columns = label,
    rows = label %in% ae_categories,
    indent = 0
  )

为什么不用tbl_hierarchical?

tbl_hierarchical的核心设计目标是处理层级嵌套的变量(比如“消化系统疾病”下的“恶心”“呕吐”),它会默认按变量的层级关系汇总计数,所以天然不适合你的独立类别统计需求。而tbl_summary配合数据预处理,能更灵活地实现非嵌套的唯一受试者计数场景。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.07 08:04:30