如何将未知参数集传递给 R 函数

How pass unknown set of parameters to R function

我有一个类似

的函数
myfunc <- function(x, y=x){
  x+y
}

如果没有将 y 传递给函数,那么(显然)会将 y 的值默认为 x。

现在,我正在使用 optparse 读取一些命令行参数到调用 myfunc.

的脚本
# myscript.R

option_list <- list(
  make_option(c("--x"), type="numeric"),
  make_option(c("--y"), type="numeric")
)

print(myfunc(opt$x, opt$y))

上面代码的问题是,它强制用户为 y 提供一个值(否则会抛出错误)。相反,我想调用 myfunc 使用所有且仅使用用户提供的参数。我怎样才能以最优雅、可扩展、可概括的方式实现这一目标?

注意 - 对于那些熟悉 Python 的人,我想我想使用 opt.

中的任何值做一些类似于字典解包的事情

如果您有来自 optparse 的参数的命名列表并希望提供给函数,您可以使用 do.call:

# Provide x and y
opts <- list(x=2, y=3)
do.call(myfunc, opts)
# [1] 5

# Provide only x
opts <- list(x=2)
do.call(myfunc, opts)
# [1] 4

如您所见,这基本上是 Python 的 "dictionary unpacking"/"splatting"。 然后,您可以使用 optparse 获取 x 和 y 的值,使 y 成为命令行上的可选输入:

# optparse.R
library(optparse)
option_list <- list(make_option("--x", type="integer", default=0),
                    make_option("--y", type="integer"))
opt <- parse_args(OptionParser(option_list=option_list))
myfunc <- function(x, y=x) x+y
do.call(myfunc, opt[names(opt) %in% c("x", "y")])
# > Rscript optparse.R --x=2 --y=3
# [1] 5
# > Rscript optparse.R --x=2
# [1] 4

通过使用被调用的 R 函数来计算 y 的默认值而不是命令行解析器,可以很容易地为 y 设置更复杂的默认值,例如 y=min(0, x).

# optparse.R
library(optparse)
option_list <- list(make_option("--x", type="integer", default=0),
                    make_option("--y", type="integer"))
opt <- parse_args(OptionParser(option_list=option_list))
myfunc <- function(x, y=min(0, x)) x+y
do.call(myfunc, opt[names(opt) %in% c("x", "y")])
# > Rscript optparse.R --x=-2
# [1] -4
# > Rscript optparse.R --x=2
# [1] 2

我更喜欢更新的 docopt over optparse,因为我发现 docopt 是

  • 更易于使用(见下文)
  • 广泛适用于多种语言,请参阅 docopt.org

这里是一个最小的示例,它还提供了默认值,这是您在这里关心的问题。先上代码:

#!/usr/bin/Rscript

library(methods)    # as Rscript does not load it
library(docopt)

## simple helper function
myfunc <- function(x, y) as.numeric(x) + as.numeric(y)   

doc <- "Usage: myscript [-x x] [-y y]
 -x x  Numeric value for x [default: 0.0]
 -y y  Numeric value for y [default: -7.89]"

opt <- docopt(doc)

print(myfunc(opt$x, opt$y))

那么用法:

edd@max:/tmp$ ./myscript.R --help
Usage: myscript [-x x] [-y y]
 -x x  Numeric value for x [default: 0.0]
 -y y  Numeric value for y [default: -7.89] 
edd@max:/tmp$ ./myscript.R 
[1] -7.89
edd@max:/tmp$ ./myscript.R -y 40 -x 2
[1] 42
edd@max:/tmp$ 

请注意,我们必须对值使用 as.numeric(),因为 docopt 不做的一件事是保证/强制执行类型。