R中自定义Cox模型函数依赖全局环境的原因及解决方法
问题解答
1. 报错原因
你设置options(datadist = 'dd')时,rms包的cph函数会根据字符串'dd'去全局环境(.GlobalEnv)查找对应的datadist对象,但myfun1里的dd是定义在函数局部环境中的变量,不属于全局环境,所以cph找不到这个对象,就抛出了"dataset dd not found"的错误。
而myfun2用<<-把dd直接赋值到了全局环境,cph自然能找到对应的对象,因此可以正常运行。
2. 不暴露全局环境的解决办法
这里有几种靠谱的方式,优先推荐第一种(官方设计的标准用法):
方案一:直接给cph传datadist参数
cph本身支持通过datadist参数直接传入预处理好的对象,完全不需要依赖全局选项,这是最规范的写法:
library(survival) library(rms) data(lung) myfun1 <- function(data, x){ x = sym(x) dd = datadist(data) # 直接在cph调用里传入datadist参数 fit = rlang::inject(cph(Surv(time, status) ~ rcs(!!x), data = data, datadist = dd)) fit } myfun1(data = lung, x = 'meal.cal')
方案二:临时修改环境,用完恢复
如果一定要用options(datadist)的方式,可以把dd临时放到当前函数环境里,同时记得退出函数时恢复原来的选项,避免污染全局设置:
myfun1 <- function(data, x){ x = sym(x) dd = datadist(data) # 先保存原来的datadist设置,后面要恢复 old_dd_setting = getOption("datadist") options(datadist = 'dd') # 把dd放到当前函数环境,让cph能找到它 assign('dd', dd, envir = environment()) # 函数退出时自动恢复原来的选项 on.exit({ options(datadist = old_dd_setting) }) fit = rlang::inject(cph(Surv(time, status) ~ rcs(!!x), data = data)) fit } myfun1(data = lung, x = 'meal.cal')
方案三:用with()指定运行环境
通过with()把cph的运行环境指定为当前函数的局部环境,这样cph就能找到局部的dd了:
myfun1 <- function(data, x){ x = sym(x) dd = datadist(data) old_dd_setting = getOption("datadist") options(datadist = 'dd') on.exit(options(datadist = old_dd_setting)) fit = with(environment(), { rlang::inject(cph(Surv(time, status) ~ rcs(!!x), data = data)) }) fit } myfun1(data = lung, x = 'meal.cal')
内容的提问来源于stack exchange,提问作者zhiwei li
相关产品推荐
相关产品推荐

