繁体   English   中英

对多个 arguments 使用 match.arg 时出错

[英]Error in using match.arg for multiple arguments

我不熟悉在 R 函数中使用match.arg作为默认值规范。 我对以下行为有疑问。

trial_func <- function(a=c("1","9","20"),b=c("12","3"),d=c("55","01")){
  a <- match.arg(a)
  b <- match.arg(b)
  d <- match.arg(d)
  list(a,b,d)
}
trial_func()
# [[1]]
# [1] "1"
# 
# [[2]]
# [1] "12"
# 
# [[3]]
# [1] "55"

当我尝试对每个单独的参数使用match.arg时,它按预期工作。 但是当我尝试使用 lapply 来减少编写的代码时,会导致以下问题。

trial_func_apply <- function(a=c("1","9","20"),b=c("12","3"),d=c("55","01")){
  lapply(list(a,b,d), match.arg)
}
trial_func_apply()

FUN(X[[i]], ...) 中的错误:“arg”的长度必须为 1

我在这里错过了什么吗?

经过一番调查之后,您需要传递一个论点,即您的字符向量为NULL,即

trial_func_apply <- function(a=c("1","9","20"),b=c("12","3"),d=c("55","01")){
     lapply(list(a,b,d), function(i)match.arg(NULL, i))
 }

trial_func_apply()
#[[1]]
#[1] "1"

#[[2]]
#[1] "12"

#[[3]]
#[1] "55"

这是一个老问题,但我觉得这是一个很好的问题,所以我将尝试通过解释以下内容来提供广泛的解释:

  • 阅读?match.arg的相关文档
  • 使match.arg无法猜测选择
  • 了解match.arg在下面使用的 R 语言的三个功能。
  • 简化match.arg实现
  • 使问题的lapply示例有效

match.arg文档

用法告诉您match.arg需要您要匹配的选定选项 ( arg ) 和所有可能的choices

match.arg(arg, choices, several.ok = FALSE)

如果我们阅读choices ,我们会发现它经常会丢失,我们应该阅读更多细节...... match.arg如何在没有可能的选择的情况下工作,我们想知道?

选择:候选值的特征向量,通常缺失,请参阅“详细信息”。

也许细节部分给出了一些提示(粗体是我的):

细节:

在单参数形式“match.arg(arg)”中,选择是从调用“match.arg”的 function 的正式参数“arg”的默认设置中获得的。 (由于默认参数匹配会将 'arg' 设置为 'choices',这被允许作为 'length one unless 'several.ok' is 'TRUE'' 规则的例外,并返回第一个元素。)

因此,如果您不指定choices参数,R 将付出一些努力自动猜对它。 要使 R 魔法起作用,必须满足几个条件:

  1. 必须使用参数直接从 function 调用match.arg function
  2. 要匹配的变量的名称必须是参数的名称。

match.arg()可以被欺骗:

match.arg()无法猜测选择:

dummy_fun1 <- function(x = c("a", "b"), y = "c") {
  # If you name your argument like another argument
  y <- x
  # The guessed choices will correspond to y (how could it know they were x?)
  wrong_choices <- match.arg(y)
}

dummy_fun1(x = "a")
# Error in match.arg(y) : 'arg' should be “c”

dummy_fun2 <- function(x = c("a", "b"), y = "c") {
  # If you name your argument differently
  z <- x
  # You don't get any guess:
  wrong_choices <- match.arg(z)
}

dummy_fun2(x="a")
#Error in match.arg(z) : 'arg' should be one of

match.arg 需要和使用的三个 R 语言特性

(1) 它使用非标准评估来获取变量的名称:

whats_the_var_name_called <- function(arg) {
  as.character(substitute(arg))
}

x <- 3
whats_the_var_name_called(x)
# "x"
y <- x
whats_the_var_name_called(y)
# "y"

(2) 它使用sys.function()获取调用者 function:

this_function_returns_its_caller <- function() {  
  sys.function(1)
}

this_function_returns_itself <- function() {
  me <- this_function_returns_its_caller()
  message("This is the body of this_function_returns_itself")
  me
}

> this_function_returns_itself()
This is the body of this_function_returns_itself
function() {
  me <- this_function_returns_its_caller()
  message("This is the body of this_function_returns_itself")
  me
}

(3) 它使用formals()来获取可能的值:

a_function_with_default_values <- function(x=c("a", "b"), y = 3) {

}

formals(a_function_with_default_values)[["x"]]
#c("a", "b")

match.arg是如何工作的?

结合这些东西, match.arg使用substitute()来获取 args 变量的名称,它使用sys.function()来获取调用者 function,并在调用者 function 上使用带有参数名称的formals()来获取function 的默认值(选项):

get_choices <- function(arg, choices) {
  if (missing(choices)) {
    arg_name <- as.character(substitute(arg))
    caller_fun <- sys.function(1)
    choices_as_call <- formals(caller_fun)[[arg_name]]
    choices <- eval(choices_as_call)
  }
  choices
}

dummy_fun3 <- function(x = c("a", "b"), y = "c") {
  get_choices(x)
}
dummy_fun3()
#[1] "a" "b"

由于我们现在知道用于获得选择的魔法,所以我们可以创建我们的match.arg实现:

my_match_arg <- function(arg, choices) {
  if (missing(choices)) {
    arg_name <- as.character(substitute(arg))
    caller_fun <- sys.function(1)
    choices_as_call <- formals(caller_fun)[[arg_name]]
    choices <- eval(choices_as_call)
  }
  # Really simple and cutting corners... but you get the idea:
  arg <- arg[1]
  if (! arg %in% choices) {
    stop("Wrong choice")
  }
  arg
}

dummy_fun4 <- function(x = c("a", "b"), y = "c") { 
  my_match_arg(x)
}

dummy_fun4(x="d")
# Error in my_match_arg(x) : Wrong choice
dummy_fun4(x="a")
# [1] "a"

这就是match.arg的工作原理。

为什么它在lapply下不起作用? 如何解决?

为了猜测choices参数,我们查看调用者参数。 当我们在 lapply 调用中使用match.arg()时,调用者不是我们的 function,因此match.arg无法猜测choices 我们可以手动获取选项并手动提供选项:

trial_func_apply <- function(a=c("1","9","20"),b=c("12","3"),d=c("55","01")){
  this_func <- sys.function()
  the_args <- formals(this_func)
  default_choices <- list(
    eval(the_args[["a"]]),
    eval(the_args[["b"]]),
    eval(the_args[["d"]])
  )
  # mapply instead of lapply because we have two lists we
  # want to apply match.arg to
  mapply(match.arg, list(a,b,d), default_choices)
}
trial_func_apply()
# [1] "1"  "12" "55"

请注意,我通过不定义所有评估应该发生的环境来偷工减料,因为在上面的示例中它们按原样工作。 可能有一些极端情况会使这个示例失败,所以不要在生产中使用它们。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM