我正在尝试编写一个在R中有默认参数的函数。最后一个参数告诉我用户如何计算变量'g'。默认值为“s + a”(前两个参数的总和),但原则上它可以由任何函数指定(例如“s - a”或“s * a”......)。
myFunc <- function(n,
s = rbernoulli(n, p = 0.5),
a = rnorm(n,sd = 2),2),
g = s + a){
data.frame(s = factor(s),
a = a,
g = as.numeric(g>0))
}
如果我调用函数本身,这可以正常工作:
myFunc(5)
要指定我想要'g'的计算方式,我想这样做:
myFunc(n = 5, g = a - s) (I)
要么
myFunc(n = 5, a = ., s = ., g = a - s) (II)
似乎(I)将导致R在工作空间中查找变量s / a,这不是我想要的。并且(II)不存在,但是我的方式是“使用默认计算”。
我尝试用NULL指定我的函数,但这也不起作用。请注意,我希望能够在我的值之后在函数中使用'g'(所以我不能用函数代替它)。
我认为最好的方法是使g
成为一个接受两个参数的函数,s
和a
。然后,您可以在需要时传递不同的功能:
myFunc <- function(n,
s = purrr::rbernoulli(n, p = 0.5),
a = rnorm(n, sd = 2),
g = function(s, a) { s + a }) {
g_val = g(s, a)
data.frame(s = factor(s),
a = a,
g = as.numeric(g_val > 0))
}
myFunc(5)
myFunc(5, g = function(s, a) { s - a })
问题是g
在调用环境中进行评估,而不是在myFunc
中的环境中进行评估。您可以添加一个参数来指定评估g
的环境,并使用默认值environment()
,以便它默认为myFunc2
中的环境。
myFunc2 <- function(n,
s = rbernoulli(n, p = 0.5),
a = rnorm(n,sd = 2),
g,
envir = environment()) {
g <- if (missing(g)) s + a else eval(substitute(g), envir)
data.frame(s = factor(s),
a = a,
g = as.numeric(g>0))
}
myFunc2(n = 5, g = s + a)
这可以使用非标准评估来完成。有许多方法可以实施。我现在大多使用quosures和rlang::eval_tidy
。以下是使用此函数实现的函数:
library(purrr)
library(rlang)
myFunc <- function(
n,
s = rbernoulli(n, p = 0.5),
a = rnorm(n, sd = 2),
g = s + a) {
if (!missing(g)) {
g <- eval_tidy(enquo(g), list(s = s, a = a))
}
data.frame(s = factor(s),
a = a,
g = as.numeric(g>0))
}
这将使用您建议的示例myFunc(n = 5, g = a - s)
。如果未提供g
参数,则默认为在其他参数的上下文中评估默认表达式的标准r功能。
另请注意,这适用于quasiquotation,因此您可以执行以下操作:
my_expr <- expr(a - s)
myFunc(n = 5, g = !!my_expr)
在couple of有非标准评估的great chapters Hadley Wickham's Advanced R。
仅使用基数R(您提供的purrrr:bernoulli
除外):
library(purrr)
myFunc <- function(
n,
s = rbernoulli(n, p = 0.5),
a = rnorm(n, sd = 2),
g = s + a) {
if (!missing(g)) {
g <- eval(substitute(g), list(s = s, a = a))
}
data.frame(s = factor(s),
a = a,
g = as.numeric(g>0))
}