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

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")选择器写法无法正常运行
修正方案

首先修复代码里的基础笔误:

  1. 调用tbl_summary时传入的数据集名错误,原代码写的是不存在的data,实际应该是前面预处理好的pdata
  2. 注释掉的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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 19:09:21