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

使用gtsummary合并事件/受试者层级统计表遇两类问题求助

问题:堆叠事件级与受试者级统计表格时的表头N丢失及行分组问题

我需要创建一个首行为事件级计数、后续为受试者级计数的统计表格,编写的R代码如下:

# Read in data
adsl <- cards::ADSL %>%
  mutate(TRTA = TRT01A)

adcm <- pharmaverseadam::adcm %>%
  filter(SAFFL == "Y" & ONTRTFL == 'Y') %>%
  select(c(USUBJID, TRTA, CMTRT, CMCLAS, CMDECOD, ONTRTFL))

# Event level counts
tbl1 <- adcm %>% tbl_hierarchical_count(
  by = TRTA,
  variables = c(CMTRT),
  overall_row = TRUE,
  label = list(..ard_hierarchical_overall.. = "TOTAL NUMBER OF CONCOMITANT MEDICATIONS")
  ) %>% add_overall(last = TRUE)

tbl1$table_body <- tbl1$table_body %>%
  filter(grepl("ard_hierarchical", variable))

# Subject level counts
tbl2 <- adcm %>% tbl_hierarchical(
  by = c(TRTA),
  variables = c(CMCLAS, CMDECOD),
  denominator = adsl,
  id = USUBJID,
  include = everything(),
  statistic = everything() ~ "{n} ({p}%)",
  overall_row = TRUE,
  label = list(
    ..ard_hierarchical_overall.. = "NUMBER OF PARTICIPANTS WITH ANY CONCOMITANT MEDICATION")
  ) %>%
  add_overall(last = TRUE)

# Stack the tables together
tbl.final <- tbl_stack(list(tbl1, tbl2),
                       quiet = TRUE) %>%
  # Modify the zero percent
  modify_table_body(
    ~ .x %>%
      dplyr::mutate(across(
        all_stat_cols(), ~ dplyr::case_when(. == "0.0 (0.00)" ~ "0", TRUE ~ .)
      ))) %>%
  # Update header
  modify_header(
    all_stat_cols() ~ "**{level}**  \n(N = {n}) <br>n(%)",
    label ~ "**ATC Level 4 <br> Preferred Term**") %>%
  # Remove default footnote
  remove_footnote_header(columns = all_stat_cols()) %>%
  # Create GT for print
  as_gt()

tbl.final$`_data` <- tbl.final$`_data` %>%
  mutate(tbl_id1 = if_else(!grepl("ard_hierarchical", variable),3,tbl_id1))

# Add blank rows for each tbl_id1
tbl.final <- tbl.final %>%
  gt::tab_row_group(
    label = md("<br>"),
    rows = tbl_id1 <= 1
  ) %>%
  tab_options(row_group.default_label = md("<br>"))

目前遇到两个问题:

  • 问题1:tbl2原本包含表头N计数,但堆叠生成tbl.final后该信息丢失,输出显示N=NA;
  • 问题2:尝试使用tab_row_group插入指定空白行(黄色高亮区域),借助tbl_id信息实现但未达预期效果。

解决方案

问题1:修复表头N丢失问题

堆叠表格时,tbl_stack不会自动合并两个表格的分母统计信息,导致表头动态变量{n}无法正确提取。解决方式是提前从原始数据中提取各治疗组的样本量,手动构建表头标签:

# 提前提取各治疗组及总体的样本量
trt_n <- adsl %>%
  group_by(TRTA) %>%
  summarise(n = n_distinct(USUBJID)) %>%
  bind_rows(tibble(TRTA = "Overall", n = n_distinct(adsl$USUBJID)))

# 构建带样本量的表头标签
header_labels <- setNames(
  paste0("**", trt_n$TRTA, "**  \n(N = ", trt_n$n, ") <br>n(%)"),
  trt_n$TRTA
)

之后在modify_header中替换动态模板,使用自定义标签:

modify_header(
  all_stat_cols() ~ header_labels[cur_column()],
  label ~ "**ATC Level 4 <br> Preferred Term**"
)

问题2:修复空白行插入问题

tbl_stack后会自动生成tbl_id列,标记行来自第一个表格(tbl_id=1)还是第二个表格(tbl_id=2),无需手动创建tbl_id1。最简单的方式是在堆叠前给tbl1末尾添加空白行,实现两段内容的分隔:

# 给tbl1添加空白行
tbl1_empty <- tbl1 %>%
  modify_table_body(
    ~ .x %>%
      add_row(label = "", variable = "", .before = nrow(.))
  )

# 堆叠带空白行的tbl1和tbl2
tbl.final <- tbl_stack(list(tbl1_empty, tbl2), quiet = TRUE)

如果需要更清晰的分段提示,还可以用tab_row_group给两段内容添加分组标题:

tbl.final <- tbl.final %>%
  gt::tab_row_group(
    label = md("**事件级计数**"),
    rows = 1:(nrow(tbl1$table_body))
  ) %>%
  gt::tab_row_group(
    label = md("**受试者级计数**"),
    rows = (nrow(tbl1$table_body)+2):nrow(.)
  ) %>%
  tab_options(row_group.font.weight = "bold")

修改后的完整代码

# Read in data
adsl <- cards::ADSL %>%
  mutate(TRTA = TRT01A)

adcm <- pharmaverseadam::adcm %>%
  filter(SAFFL == "Y" & ONTRTFL == 'Y') %>%
  select(c(USUBJID, TRTA, CMTRT, CMCLAS, CMDECOD, ONTRTFL))

# Event level counts
tbl1 <- adcm %>% tbl_hierarchical_count(
  by = TRTA,
  variables = c(CMTRT),
  overall_row = TRUE,
  label = list(..ard_hierarchical_overall.. = "TOTAL NUMBER OF CONCOMITANT MEDICATIONS")
) %>% add_overall(last = TRUE)

tbl1$table_body <- tbl1$table_body %>%
  filter(grepl("ard_hierarchical", variable))

# Subject level counts
tbl2 <- adcm %>% tbl_hierarchical(
  by = c(TRTA),
  variables = c(CMCLAS, CMDECOD),
  denominator = adsl,
  id = USUBJID,
  include = everything(),
  statistic = everything() ~ "{n} ({p}%)",
  overall_row = TRUE,
  label = list(
    ..ard_hierarchical_overall.. = "NUMBER OF PARTICIPANTS WITH ANY CONCOMITANT MEDICATION")
) %>%
  add_overall(last = TRUE)

# 提前提取各治疗组及总体的样本量
trt_n <- adsl %>%
  group_by(TRTA) %>%
  summarise(n = n_distinct(USUBJID)) %>%
  bind_rows(tibble(TRTA = "Overall", n = n_distinct(adsl$USUBJID)))

# 构建表头标签
header_labels <- setNames(
  paste0("**", trt_n$TRTA, "**  \n(N = ", trt_n$n, ") <br>n(%)"),
  trt_n$TRTA
)

# 给tbl1添加空白行
tbl1_empty <- tbl1 %>%
  modify_table_body(
    ~ .x %>%
      add_row(label = "", variable = "", .before = nrow(.))
  )

# Stack the tables together
tbl.final <- tbl_stack(list(tbl1_empty, tbl2), quiet = TRUE) %>%
  # Modify the zero percent
  modify_table_body(
    ~ .x %>%
      dplyr::mutate(across(
        all_stat_cols(), ~ dplyr::case_when(. == "0.0 (0.00)" ~ "0", TRUE ~ .)
      ))) %>%
  # Update header with custom N values
  modify_header(
    all_stat_cols() ~ header_labels[cur_column()],
    label ~ "**ATC Level 4 <br> Preferred Term**") %>%
  # Remove default footnote
  remove_footnote_header(columns = all_stat_cols()) %>%
  # Create GT for print
  as_gt()

# 添加分组标题分隔两段内容
tbl.final <- tbl.final %>%
  gt::tab_row_group(
    label = md("**事件级计数**"),
    rows = 1:(nrow(tbl1$table_body))
  ) %>%
  gt::tab_row_group(
    label = md("**受试者级计数**"),
    rows = (nrow(tbl1$table_body)+2):nrow(.)
  ) %>%
  tab_options(row_group.font.weight = "bold")

内容的提问来源于stack exchange,提问作者Ranjan Karmakar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 11:28:11