do.call R 中的一个函数,无需加载包

do.call a function in R without loading the package

我想 do.call 包中的(导出的)函数,需要在 what 参数中将包和函数指定为字符串(即,当包未加载时进入我的环境或存在潜在的函数名称冲突)。

函数名是一个类似"lme4::lmer"的字符串,它指定包和函数。

例如,有条件地调用一个函数(类似于this question):

FUN = if(TRUE) {
  "lme4::lmer"
} else {
  "nlme::nmle"
}

args.list = list(Reaction ~ Days + (Days | Subject), 
                 quote(lme4::sleepstudy))

do.call(what=FUN, args=args.list)
# Error in `lme4::lmer`(Reaction ~ Days + (Days | Subject), lme4::sleepstudy) : 
#   could not find function "lme4::lmer"

其他方法可行但不是我需要的:

# Load the package and use only the function string 
library(lme4)
do.call("lmer", ...)

# Or calling the function directly: 
lme4::lmer(...)
do.call(eval(parse(text="lme4::lmer")), ...)

eval with parse 会起作用!

> tmp <- expand.grid(letters[1:2], 1:3, c("+", "-"))
> do.call(eval(parse(text='stringr::str_c')), c(tmp, sep = ""))

 [1] "a1+" "b1+" "a2+" "b2+" "a3+" "b3+" "a1-" "b1-" "a2-" "b2-" "a3-" "b3-"

参考:https://www.r-bloggers.com/converting-a-string-to-a-variable-name-on-the-fly-and-vice-versa-in-r/

您不能在字符串中包含 ::,因为 :: 是一个函数。该字符串未被评估和解析。 do.call 只是假定存在同名函数。就像::一样,$也是一个函数所以这也行不通

a<-list(f=function(x) x+1)
do.call(a$f, list(4))
# [1] 5
do.call("a$f", list(4))
# Error in do.call("a$f", list(4)) : could not find function "a$f"

如果您希望能够从命名空间中找到函数,您可以编写一个辅助函数来解析包含 ::

的值
getfun<-function(x) {
    if(length(grep("::", x))>0) {
        parts<-strsplit(x, "::")[[1]]
        getExportedValue(parts[1], parts[2])
    } else {
        x
    }
}
getfun("lme4::lmer")

这应该有效

do.call(getfun("lme4::lmer"), list(
    Reaction ~ Days + (Days | Subject), 
    quote(lme4::sleepstudy)))