簡體   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