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

时间:2015-08-23 15:24:04

标签: r optparse

我有一个像

这样的功能
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内的任何值来执行与字典解包类似的操作。

2 个答案:

答案 0 :(得分:3)

如果您有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

答案 1 :(得分:2)

我更喜欢较docopt而不是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没有做的一件事就是保证/强制执行某种类型。