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

如何用gt/gtsummary按第二变量自动生成行组或表头?

长格式计数数据按分类变量生成行组的程序化实现(gt/gtsummary)

我需要对长格式计数数据,按照第二个分类变量进行汇总,希望用gt或gtsummary工具,程序化地基于主变量对应的分类变量插入行表头(用tab_row_group()生成行组),而非手动指定行号或匹配标签。

示例数据

library(gt)
library(gtsummary)
library(tidyverse)

aes <- data.frame(
  preferred_term = c("Headache", "Fatigue", "Anxiety", "Anxiety", "Headache",
                     "Contusion", "Depressed Mood", "Gait disturbance"),
  system_organ_class = c("Nervous System Disorders",
                         "General disorders and administration site conditions",
                         "Psychiatric disorders", "Psychiatric disorders",
                         "Nervous System Disorders", 
                         "Skin and subcutaneous tissue disorders",
                         "Psychiatric disorders",
                         "General disorders and administration site conditions")
)

一、手动用gt实现(非程序化)

该方法需要手动指定每个行组的标签和对应行号,数据变动时需手动调整,灵活性差:

left_join(
  aes %>% 
    group_by(preferred_term) %>% 
    summarize(n = n()) %>% 
    mutate(
      p = round((n / sum(n)) * 100, 1),
      n_p = paste0(n, " (", p, ")")
    ),
  aes %>% 
    distinct(),
  by = "preferred_term"
) %>% 
  arrange(system_organ_class) %>% 
  select(-c(n, p, system_organ_class)) %>% 
  gt() %>% 
  tab_row_group(
    label = "General disorders and administration site conditions", rows = 1:2
  ) %>% 
  tab_row_group(
    label = "Nervous System Disorders", rows = 3:3
  ) %>% 
  tab_row_group(
    label = "Psychiatric disorders", rows = 4:5
  ) %>% 
  tab_row_group(
    label = "Skin and subcutaneous tissue disorders", rows = 6:6
  )

二、用gtsummary生成宽格式汇总(不符合需求)

tbl_summary(by = ...)会生成按分类变量分列的宽格式表格,不是行组形式,无法满足按分类变量分组展示行的需求:

aes %>%
  tbl_summary(by = system_organ_class)

三、手动用gtsummary+modify_table_body实现(非程序化)

通过case_when手动匹配术语和分类组,数据更新时需修改匹配规则,同样缺乏灵活性:

aes %>% 
  tbl_summary(
    include = preferred_term
  ) %>%
  modify_table_body(
    mutate,
    groupname_col = case_when(
      label %in% c("Fatigue", "Gait disturbance") ~ "General disorders and administration site conditions",
      label == "Headache" ~ "Nervous System Disorders",
      label %in% c("Anxiety", "Depressed Mood") ~ "Psychiatric disorders",
      label == "Contusion" ~ "Skin and subcutaneous tissue disorders",
      TRUE ~ ""
    )
  )

四、程序化解决方案

方案1:gtsummary实现(推荐)

先提取术语与分类组的映射关系,再通过left_join关联到汇总表中,自动生成行组,无需手动匹配:

aes %>% 
  tbl_summary(include = preferred_term) %>%
  modify_table_body(
    ~ .x %>%
      # 关联术语对应的分类组
      left_join(
        aes %>% distinct(preferred_term, system_organ_class),
        by = c("label" = "preferred_term")
      ) %>%
      # 将分类组设为行组列
      rename(groupname_col = system_organ_class) %>%
      # 按分类组和术语排序
      arrange(groupname_col, label)
  ) %>%
  # 优化表头显示
  modify_header(label = "不良反应术语") %>%
  bold_labels()

方案2:gt实现

先整理汇总数据,再通过循环自动为每个分类组添加行组,无需手动指定行号:

# 第一步:汇总并整理数据,保留分类组信息
aes_summary <- aes %>%
  group_by(system_organ_class, preferred_term) %>%
  summarize(n = n(), .groups = "drop") %>%
  mutate(
    p = round(n / sum(n) * 100, 1),
    n_p = paste0(n, " (", p, ")")
  ) %>%
  arrange(system_organ_class, preferred_term)

# 第二步:初始化gt表格
gt_table <- aes_summary %>%
  select(preferred_term, n_p) %>%
  gt() %>%
  cols_label(preferred_term = "不良反应术语", n_p = "例数(%)")

# 第三步:循环添加行组
unique_soc <- unique(aes_summary$system_organ_class)
for (soc in unique_soc) {
  # 获取当前分类组对应的所有术语
  term_list <- filter(aes_summary, system_organ_class == soc)$preferred_term
  gt_table <- gt_table %>%
    tab_row_group(label = soc, rows = preferred_term %in% term_list)
}

gt_table

内容的提问来源于stack exchange,提问作者Raoul Duke

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 18:29:56