gtsummary包add_difference()向自定义检验函数传参失败问题
问题描述
在R语言使用gtsummary包的tbl_summary() |> add_difference()调用链路中,自定义统计检验函数无法正确接收add_difference()里test.args传入的参数:自定义函数可被正常触发,但传入的自定义参数始终取默认值NULL,移除默认值会直接报参数缺失错误,官方文档提到的all_tests()选择器写法也无法正常生效。
复现代码
自定义检验函数
library(tidyverse) library(gtsummary) # 适配add_difference()要求的自定义检验函数 testMe <- function(data, variable, by, group = NULL, type = NULL, conf.level = 0.95, adj.vars = NULL, # 无法正常接收传参的自定义参数 test_name = NULL, ci_type = 0.95, continuous_variable = NULL, na.rm, ...) { # 将字符串变量名转为标准引用 variable <- ensym(variable) by <- ensym(by) # 调用infer包做统计计算 estimate <- data |> specify(expr(!!variable ~ !!by)) |> calculate(stat = test_name, na.rm = na.rm) booted <- data |> specify(expr(!!variable ~ !!by)) |> generate(reps = 1000, type = "bootstrap") |> calculate(stat = test_name, na.rm = na.rm) result_df <- get_confidence_interval(booted, estimate, type = "bias-corrected", point_estimate = estimate) |> rename(conf.low = lower_ci, conf.high = upper_ci) # 按gtsummary要求返回指定列名的结果数据框 return(result_df) }
gtsummary调用代码
# 按add_difference()要求将分组变量转为字符型,仅保留2个组做对比 pdata <- PlantGrowth |> filter((group == "trt1") | (group == "trt2")) |> mutate(group = as.character(group)) table <- data |> tbl_summary( by = group, statistic = list(all_continuous() ~ "{median} ({p25}—{p75})"), ) |> add_difference( test = list(weight ~ "testMe"), # 尝试传入infer包计算需要的统计量名称参数 test.args = weight ~ list(test_name = "diff in medians") # 文档提及的选择器写法同样失效 # test.args = all_tests("testMe) ~ list(test_name = "diff in medians") )
故障表现
- 自定义函数
testMe可被正常调用 - 函数内
test_name参数始终为默认值NULL,后续计算因该参数为空报错 - 给
test_name设置合法默认值时函数可正常返回结果,确认传参环节未生效 - 移除
test_name默认值会直接触发「参数缺失」报错 all_tests("testMe")选择器写法无法正常运行
修正方案
首先修复代码里的基础笔误:
- 调用
tbl_summary时传入的数据集名错误,原代码写的是不存在的data,实际应该是前面预处理好的pdata - 注释掉的
all_tests()写法里引号未闭合,"testMe缺少后引号
传参失效的核心原因:gtsummary的add_difference()对自定义检验函数的参数匹配有严格规则,给test参数传函数名字符串时,内部命名空间匹配容易出错,导致test.args的参数无法正确映射到目标函数;另外自定义函数的返回值、形参设置不符合包规范时,也会打断传参流程。
修正后的可运行代码:
library(tidyverse) library(gtsummary) library(infer) testMe <- function(data, variable, by, group = NULL, type = NULL, conf.level = 0.95, adj.vars = NULL, na.rm = TRUE, # 自定义参数放在固定参数之后、...之前 test_name = NULL, ...) { variable <- ensym(variable) by <- ensym(by) estimate <- data |> specify(formula = expr(!!variable ~ !!by)) |> calculate(stat = test_name, na.rm = na.rm) booted <- data |> specify(formula = expr(!!variable ~ !!by)) |> generate(reps = 1000, type = "bootstrap") |> calculate(stat = test_name, na.rm = na.rm) result_df <- get_confidence_interval( booted, type = "bias-corrected", point_estimate = estimate ) |> rename(conf.low = lower_ci, conf.high = upper_ci) # 补充gtsummary要求必须返回的estimate列 result_df$estimate <- estimate$stat return(result_df) } pdata <- PlantGrowth |> filter(group %in% c("trt1", "trt2")) |> mutate(group = as.character(group)) table <- pdata |> tbl_summary( by = group, statistic = list(all_continuous() ~ "{median} ({p25}—{p75})") ) |> add_difference( test = list(all_continuous() ~ testMe), # 直接传函数对象,不要传字符串 test.args = all_tests("testMe") ~ list(test_name = "diff in medians") )
关键修正点:
- 不要给
test参数传函数名字符串,直接传函数对象本身,避免命名空间查找失败导致的传参映射断裂 test和test.args的选择器要匹配,用all_tests("testMe")时保证引号闭合,且函数已在当前环境定义- 自定义函数返回结果必须包含
estimate、conf.low、conf.high三列,原代码漏写estimate列,即使传参成功也会触发格式报错 - 形参里的
na.rm必须设置默认值,gtsummary内部调用时不会自动传递该参数 - 原代码调用
get_confidence_interval时多传了一个无效的位置参数estimate,删除后通过point_estimate参数传值即可 - 补充加载
infer包,specify、generate等统计计算函数属于infer包,tidyverse不会默认加载该包
内容的提问来源于stack exchange,提问作者Marco B
相关产品推荐
相关产品推荐

