如何用tbl_cross展示配对表并添加自定义McNemar mid-p检验?
问题与解决方案
问题背景
已知可通过tbl_summary执行McNemar检验,但更倾向于用tbl_cross展示交叉表结果。需要采用mid-p检验计算McNemar检验的p值,不过tbl_cross的add_p()函数存在自定义方法限制:指定自定义函数mcnemar_stats后,实际仍调用Fisher精确检验,希望找到既能使用自定义检验方法,又保留tbl_cross输出格式的方案。
解决方案
tbl_cross的add_p()默认适配独立样本的检验方法,直接传递自定义配对样本检验函数会被覆盖。可以通过先生成交叉表,再手动插入自定义检验结果的方式解决,具体步骤如下:
- 用
tbl_cross生成符合需求的交叉表格式 - 编写正确的mid-p版McNemar检验函数(修复原函数中未定义的变量问题)
- 计算mid-p值后,通过
modify_table_body()将结果插入表格,保持原有格式
修正后的完整代码
# 加载所需包 library(gtsummary) library(dplyr) library(tidyr) # 生成模拟数据集:100例受试者的Week16和Week32应答数据 set.seed(123) subject_ids <- paste0("SUBJ", sprintf("%03d", 1:100)) dummy_data <- data.frame( USUBJID = rep(subject_ids, each = 2), AVISIT = rep(c("Week 16", "Week 32"), times = 100) ) # 生成有相关性的应答数据 set.seed(456) responses <- vector("character", length = 200) for (i in seq(1, 199, by = 2)) { responses[i] <- sample(c("Yes", "No"), 1, prob = c(0.3, 0.7)) responses[i+1] <- ifelse(responses[i] == "Yes", sample(c("Yes", "No"), 1, prob = c(0.7, 0.3)), sample(c("Yes", "No"), 1, prob = c(0.2, 0.8))) } dummy_data$CRIT1FL <- responses # 转换为宽格式,用于配对检验 dummy_wide <- dummy_data %>% pivot_wider(id_cols = USUBJID, names_from = AVISIT, values_from = CRIT1FL) %>% mutate(across(c(`Week 16`, `Week 32`), ~factor(.x, levels = c("Yes", "No")))) # 定义mid-p版McNemar检验函数(修复变量未定义问题) mcnemar_midp <- function(data, row_var, col_var) { tbl <- table(data[[row_var]], data[[col_var]]) discordant_n <- tbl[1,2] + tbl[2,1] # 不一致对数总和 x <- min(tbl[1,2], tbl[2,1]) # 较小的不一致数 # 计算mid-p值 midp_p <- 2 * pbinom(x, discordant_n, 0.5, lower.tail = TRUE) - dbinom(x, discordant_n, 0.5) tibble(p.value = midp_p, method = "McNemar检验(mid-p法)") } # 1. 生成交叉表 cross_table <- dummy_wide %>% tbl_cross(row = `Week 16`, col = `Week 32`, percent = "cell") %>% modify_header(p.value = "**McNemar P值**") %>% modify_footnote(p.value ~ "采用mid-p法计算") %>% modify_fmt_fun(p.value = label_style_sigfig(digits = 3)) # 2. 计算mid-p值 midp_result <- mcnemar_midp(dummy_wide, "Week 16", "Week 32") # 3. 将p值插入交叉表,替换默认的Fisher检验结果 final_table <- cross_table %>% modify_table_body( ~.x %>% mutate(p.value = ifelse(row_type == "label", midp_result$p.value, p.value)) ) # 展示结果 final_table
关键说明
- 原函数中未定义的
n变量修正为discordant_n(不一致对数总和),这是mid-p检验的正确计算基础 - 通过
modify_table_body()精准替换表格中的p值,完全保留tbl_cross的原有格式 - 自定义函数专注于计算mid-p值,与表格生成逻辑分离,避免
add_p()的默认行为干扰
内容的提问来源于stack exchange,提问作者xiecheng gu
相关产品推荐
相关产品推荐

