假设我们有一个函数调用 stats::lm
并将公式和数据框作为参数。可以使用可变参数提供我们想要传递给 stats::lm
的更多参数:
outer_function <- function(formula, data, ...) {
z <- stats::lm(formula = formula, data = data, ...)
return(z)
}
现在假设我们要使用这个函数并提供一个附加参数 (weights
),该参数将传递给 stats::lm
。
data <- data.frame(replicate(5, rnorm(100)))
weights <- replicate(100, 1)
formula <- X1 ~ X2 + X3
outer_function(formula = formula, data = data, weights = weights)
这会在 stats::lm
中产生以下错误:
Error in eval(extras, data, env) :
..1 used in an incorrect context, no ... to look in
调试对 stats::lm
的调用 我看到参数 weights
已正确传递给 stats::lm
,但是 match.call()
,后面在函数中用来求值,就是
stats::lm(formula = formula, data = data, weights = ..1)
weights
被分配给 ...
-list 的第一个元素,它是空的。
谁能详细说明这种方法失败的原因?特别是,如果 weights
是一个标量(比如说 5),那么问题就不会出现,而 match.call()
会是
stats::lm(formula = formula, data = data, weights = 5)
目前,我正在为我的功能使用以下解决方案:
outer_function <- function(formula, data, ...) {
args <- list(formula = formula, data = data, ...)
z <- do.call(stats::lm, args)
return(z)
}
这行得通,但我仍然想知道如果 ...
中的参数是向量或列表,是否没有办法绕过 do.call
。
我想不出像 do.call
这样安全和简洁的解决方法.我可以解释发生了什么,调试了lm
打电话。
在 lm
的正文中, 你会发现声明
mf <- eval(mf, parent.frame())
在作业的右侧,mf
是电话
stats::model.frame(formula = formula, data = data, weights = ..1,
drop.unused.levels = TRUE)
和parent.frame()
是outer_function
的框架调用(换句话说,评估环境 outer_function
)。 eval
正在评估 mf
在 parent.frame()
.由于 S3 调度,最终在 parent.frame()
中评估的内容是电话
stats::model.frame.default(formula = formula, data = data, weights = ..1,
drop.unused.levels = TRUE)
在 model.frame.default
的正文中, 你会发现声明
extras <- eval(extras, data, env)
在这个作业的右边,extras
是电话
list(weights = ..1)
指定来自 mf
的参数与正式参数匹配 ...
的 model.frame.default
(只是 weights
,在这种情况下,因为 model.frame.default
形式参数名为 formula
、 data
和 drop.unused.levels
); data
是包含模拟数据的数据框;和 env
是您的全局环境。 ( env
之前在 model.frame.default
的主体中定义为 environment(formula)
,这确实是您的全局环境,因为这是您定义 formula
的地方。)
eval
正在评估 extras
在 data
与 env
作为外壳。 此处 会抛出错误,因为数据框 data
和您的全局环境 env
不是 ..n
的有效上下文.符号 ..1
仅在带有 ...
的函数的框架中有效作为正式论证。
您可能已经从 ?lm
中推断出了问题,其中指出:
All of weights
, subset
and offset
are evaluated in the same way as variables in formula
, that is first in data
and then in the environment of formula
.
weights
时没有问题在 outer_function
中被赋予常量值(即,不是绑定(bind)在环境中的变量的名称,不是函数调用)打电话,因为在那种情况下match.call
不替换符号 ..n
.因此
outer_function(formula = formula, data = data, weights = 5)
有效(好吧,抛出一个不同的错误),但是
weights <- 5
outer_function(formula = formula, data = data, weights = weights)
和
outer_function(formula = formula, data = data, weights = rep(1, 100))
不要。