如何在R中匹配函数参数的许多组合?



我们可以创建一个二维数组来匹配两个函数参数的组合吗?

例如,如果我写一个函数,只有一个参数(除了数据输入参数):

choose_procedure <- function(x, what_to_do) {
switch(what_to_do,
"mean"   = {...}, # mean(x) or mean(x, na.rm = TRUE) or weighted.mean(x)
"median" = {...}, # median(x)
"square" = {...}, # x * x or x ^ 2
"unique" = {...}, # unique(x)
"log"    = {...}  # log(x) or log10(x)
)
}

我添加了内联注释,以暗示每个what_to_do输入可能有多个选择。

what_to_do="mean"时,是mean(x, na.rm = TRUE)还是mean(x, na.rm = FALSE)?同样,当what_to_do="log"时,应该是log(x)还是log10(x)?等。

为了处理这个问题,我想给choose_procedure()引入另一个参数,叫做"scenario"。所以如果对choose_procedure()的调用是:
choose_procedure(x = mtcars$mpg, what_to_do = "log", scenario = "A")

然后执行log(mtcars$mpg)
但是如果调用是

choose_procedure(x = mtcars$mpg, what_to_do = "log", scenario = "B")

则执行log10(mtcars$mpg)


"log""scenario"的示例描述了一个2x2数组:

  • "what_to_do"有2个选项:log()log10()
  • "scenario"有两个选项:"A""B"

显然,这可以用4个if语句来处理(每个组合一个),但如果我们有更多的组合(如我开始的choose_procedure()示例),将变得非常难以编程。

我有两个问题:

  1. 我正在寻找一个可以扩展到潜在的任何n×n数组的设置。
  2. 事实上,也许有一种方法可以推广到多于n×n?例如,如果我们有3个参数:"what_do_to","scenario","sub_scenario"。等。
choose_procedure <- function(x, FUN, ...){
if(...length()) FUN(x, ...)
else FUN(x)
}
x <- c(1,3,5,NA, 10)
choose_procedure(x, mean)
[1] NA
choose_procedure(x, mean, na.rm = TRUE)
[1] 4.75
choose_procedure(x, log)
[1] 0.000000 1.098612 1.609438       NA 2.302585
choose_procedure(x, log10)
[1] 0.0000000 0.4771213 0.6989700        NA 1.0000000

这是解决问题的许多方法之一,最好的方法很可能取决于您实际想要在其中使用它的上下文。然而,在你概述的情况下,我将如何处理它:

choose_procedure <- function(x, ...) {

# Define a table of options
choices <- tibble::tribble(
~what_to_do,  ~scenario,                ~result,
"mean",        "A",                   mean,
"mean",        "B", ~mean(., na.rm = TRUE),
"mean",        "C",          weighted.mean,
"median",        "A",                 median,
"square",        "A",                 ~. * .,
"square",        "B",                 ~. ^ 2,
"unique",        "A",                 unique,
"log",        "A",                    log,
"log",        "B",                  log10
)

# Filter the table down to the desired option
choice <- dplyr::filter(choices, ...)

# Stop if no options available
if (nrow(choice) == 0) {
stop("No such option available")
}

# Warn if multiple options available, and use first
if (nrow(choice) > 1) {
choice <- head(choices, 1)
warning("More than one option available, using first scenario")
}

# Transform any purrr-style lambda functions to normal functions
fun <- rlang::as_function(choice$result[[1]])

# Perform the calculation
fun(x)

}
choose_procedure(x = mtcars$mpg, what_to_do == "log", scenario == "B")
#>  [1] 1.322219 1.322219 1.357935 1.330414 1.271842 1.257679 1.155336 1.387390
#>  [9] 1.357935 1.283301 1.250420 1.214844 1.238046 1.181844 1.017033 1.017033
#> [17] 1.167317 1.510545 1.482874 1.530200 1.332438 1.190332 1.181844 1.123852
#> [25] 1.283301 1.436163 1.414973 1.482874 1.198657 1.294466 1.176091 1.330414

由reprex包(v2.0.0)于2018-10-25创建

最新更新