在 R 中 stats::lm 中使用变量参数(点-点-点)
Use of variable arguments (dot-dot-dot) in stats::lm in R
假设我们有一个调用 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
就被赋予了 ...
列表的第一个元素,它是空的。
任何人都可以详细说明为什么这种方法会失败吗?特别是,如果 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
正在评估 parent.frame()
中的 mf
。由于 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
正在评估 data
中的 extras
并将 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
被赋予常量值时没有问题(即 而不是 环境中绑定的变量名称和 not 函数调用)在 outer_function
调用中,因为在那种情况下 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))
不要。
假设我们有一个调用 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
就被赋予了 ...
列表的第一个元素,它是空的。
任何人都可以详细说明为什么这种方法会失败吗?特别是,如果 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
正在评估 parent.frame()
中的 mf
。由于 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
正在评估 data
中的 extras
并将 env
作为附件。 此处 会引发错误,因为数据框 data
和您的全局环境 env
不是 ..n
的有效上下文。符号 ..1
仅在以 ...
作为正式参数的函数的框架中有效。
您可能已经从 ?lm
中推断出了问题,其中指出:
All of
weights
,subset
andoffset
are evaluated in the same way as variables informula
, that is first indata
and then in the environment offormula
.
当 weights
被赋予常量值时没有问题(即 而不是 环境中绑定的变量名称和 not 函数调用)在 outer_function
调用中,因为在那种情况下 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))
不要。