[英]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 魔法起作用,必須滿足幾個條件:
match.arg
functionmatch.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
(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.