简体   繁体   English

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

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

I am new to using match.arg for default value specification in R functions.我不熟悉在 R 函数中使用match.arg作为默认值规范。 And I have a query regarding the below behavior.我对以下行为有疑问。

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"

When I try using match.arg for each individual argument, it works as expected.当我尝试对每个单独的参数使用match.arg时,它按预期工作。 But when I try to use an lapply to reduce the code written, it causes the below issue.但是当我尝试使用 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()

Error in FUN(X[[i]], ...): 'arg' must be of length 1 FUN(X[[i]], ...) 中的错误:“arg”的长度必须为 1

Am I missing something here?我在这里错过了什么吗?

After investigating a bit, you need to pass the argument that your character vector is NULL, ie 经过一番调查之后,您需要传递一个论点,即您的字符向量为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"

It's an old question, but I feel it's a great one, so I will try to provide extensive explanation for it by explaining the following:这是一个老问题,但我觉得这是一个很好的问题,所以我将尝试通过解释以下内容来提供广泛的解释:

  • Read the relevant documentation for ?match.arg阅读?match.arg的相关文档
  • Make match.arg fail to guess the choices使match.arg无法猜测选择
  • Learn three features of the R language that match.arg uses underneath.了解match.arg在下面使用的 R 语言的三个功能。
  • Simplified match.arg implementation简化match.arg实现
  • Make the lapply example of the question work使问题的lapply示例有效

match.arg documentation match.arg文档

The usage tells you that match.arg needs the selected option you want to match ( arg ) and all the possible choices :用法告诉您match.arg需要您要匹配的选定选项 ( arg ) 和所有可能的choices

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

If we read choices , we see that it can often be missing, and we should read more in the details... How could match.arg work without having the possible choices, we wonder?如果我们阅读choices ,我们会发现它经常会丢失,我们应该阅读更多细节...... match.arg如何在没有可能的选择的情况下工作,我们想知道?

choices: a character vector of candidate values, often missing, see 'Details'.选择:候选值的特征向量,通常缺失,请参阅“详细信息”。

Maybe the Details section gives some hints (bold is mine):也许细节部分给出了一些提示(粗体是我的):

Details:细节:

In the one-argument form 'match.arg(arg)', the choices are obtained from a default setting for the formal argument 'arg' of the function from which 'match.arg' was called.在单参数形式“match.arg(arg)”中,选择是从调用“match.arg”的 function 的正式参数“arg”的默认设置中获得的。 (Since default argument matching will set 'arg' to 'choices', this is allowed as an exception to the 'length one unless 'several.ok' is 'TRUE'' rule, and returns the first element.) (由于默认参数匹配会将 'arg' 设置为 'choices',这被允许作为 'length one unless 'several.ok' is 'TRUE'' 规则的例外,并返回第一个元素。)

So, if you don't specify the choices argument, R will make a bit of effort to guess it right automagically.因此,如果您不指定choices参数,R 将付出一些努力自动猜对它。 For the R magic to work, several conditions must be fulfilled:要使 R 魔法起作用,必须满足几个条件:

  1. The match.arg function must be called directly from the function with the argument必须使用参数直接从 function 调用match.arg function
  2. The name of the variable to be matched must be the name of the argument.要匹配的变量的名称必须是参数的名称。

match.arg() can be tricked: match.arg()可以被欺骗:

Let's make match.arg() fail to guess the choices: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

Three R language features that match.arg needs and uses match.arg 需要和使用的三个 R 语言特性

(1) It uses non-standard evaluation to get the name of the variable: (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) It uses sys.function() to get the caller function: (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) It uses formals() to get the possible values: (3) 它使用formals()来获取可能的值:

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

}

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

How does match.arg work? match.arg是如何工作的?

Combining these things, match.arg uses substitute() to get the name of the args variable, it uses sys.function() to get the caller function, and it uses formals() on the caller function with the argument name to get the default values of the function (the choices):结合这些东西, 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"

Since we now know the magic used to get the choices, so we can create our match.arg implementation:由于我们现在知道用于获得选择的魔法,所以我们可以创建我们的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"

And that's how match.arg works.这就是match.arg的工作原理。

Why it does not work under lapply ?为什么它在lapply下不起作用? How to fix it?如何解决?

To guess the choices argument, we look at the caller argument.为了猜测choices参数,我们查看调用者参数。 When we use match.arg() inside an lapply call, the caller is not our function, so match.arg fails to guess the choices .当我们在 lapply 调用中使用match.arg()时,调用者不是我们的 function,因此match.arg无法猜测choices We can get the choices manually and provide the choices manually:我们可以手动获取选项并手动提供选项:

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"

Please note that I am cutting corners by not defining the environments where all the evals should happen, because in the examples above they work as-is.请注意,我通过不定义所有评估应该发生的环境来偷工减料,因为在上面的示例中它们按原样工作。 There may be some corner cases that make this examples to fail, so don't use them in production.可能有一些极端情况会使这个示例失败,所以不要在生产中使用它们。

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

相关问题 Rigraph degree()&#39;match.arg中的错误&#39; - R igraph degree() 'Error in match.arg' 警告:match.arg中的错误:&#39;arg&#39;必须为NULL或字符向量 - Warning: Error in match.arg: 'arg' must be NULL or a character vector match.arg(mvnTest)中的错误:“ arg”的长度必须为1 - Error in match.arg(mvnTest) : 'arg' must be of length 1 match.arg(regions) 中的错误:“arg”必须为 NULL 或字符向量 - Error in match.arg(regions) : 'arg' must be NULL or a character vector 匹配使用match.arg()的默认值向量,有或没有错误[R] - Matching vector of default values using match.arg() with or without error [R] Python 中的 match.arg 等效项? - match.arg equivalent in Python? match.arg 行为不一致 - match.arg behaviour not coherent 运行应用程序时出现闪亮错误:match.arg(position) 中的错误:&#39;arg&#39; 必须为 NULL 或字符向量 - Shiny Error when running App: Error in match.arg(position) : 'arg' must be NULL or a character vector emmeans错误:match.arg(type)中的错误:&#39;arg&#39;应该是“link”,“response”,“terms”之一 - emmeans error: Error in match.arg(type) : 'arg' should be one of “link”, “response”, “terms” match.arg(opt_crit)中的错误:“ arg”必须为NULL或字符向量 - Error in match.arg(opt_crit) : 'arg' must be NULL or a character vector
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM