題
如何if_else()使用dplyr 的函式使其輸出是一個函式?隨著ifelse()從base這個是微不足道的,但有if_else()不順心的事。這是預期的行為還是我只是無法正確地做到這一點?
正品
x <- 2
ifelse(x == 2, min, max)
#> function (..., na.rm = FALSE) .Primitive("min")
dplyr::if_else(x == 2, min, max)
#> Error in true[rep(NA_integer_, length(condition))]: object of type 'builtin' is not subsettable
由reprex 包( v2.0.0 )于 2021 年 12 月 4 日創建
uj5u.com熱心網友回復:
你不應該用ifelse這個。ifelse并且if_else用于向量——特別是當你的輸入是一個向量而你的輸出是一個相同長度的向量時。您不能創建函式的向量,因此ifelse回傳函式是一個糟糕的選擇。您的代碼僅在輸入長度為 1 的特殊情況下有效——這是控制/流函式if()的用途。
ifelse如果x長度 > 1,您的代碼將失敗并出現奇怪的錯誤,請嘗試設定x = 2:3并運行您的代碼。
> x = 2:3
> ifelse(x == 2, min, max)
Error in rep(yes, length.out = len) :
attempt to replicate an object of type 'builtin'
if(),另一方面,仍將檢查第一個元素并回傳第一個元素的正確結果,同時向您發出有關輸入長度的警告:
> if(x == 2) min else max
function (..., na.rm = FALSE) .Primitive("min")
Warning message:
In if (x == 2) min else max :
the condition has length > 1 and only the first element will be used
當您檢查應該始終具有長度 1 的條件時,您應該使用if(){}else{},并且結果實際上可以是任何運算式,它可以被賦值,也可以是運行的任意代碼。按預期保存ifelse(和if_else)向量。
uj5u.com熱心網友回復:
在這種情況下,我認為if_else不可行或優于 base ifelse。dplyr::if_else在其源中使用子集(if_else不帶括號使用)。要重現該錯誤,請嘗試運行min[].
我們可以嘗試通過更改代碼來“修復”該函式,該代碼旨在通過子集將輸出強制為與true和false值相同的類:
out <- true[rep(NA_integer_, length(condition))]
# to pseudocode
out <- "whatever the typeof(true) value is"
并使用:::來獲取使用的適當內部函式dplyr。
if_else <- function (condition, true, false, missing = NULL) {
if (!is.logical(condition)) {
bad_args("condition", "must be a logical vector, not {friendly_type_of(condition)}.")
}
out <- NA_integer_
out <- dplyr:::replace_with(out, condition, true, dplyr:::fmt_args(~true),
glue::glue("length of {fmt_args(~condition)}"))
out <- dplyr:::replace_with(out, !condition, false, dplyr:::fmt_args(~false),
glue::glue("length of {fmt_args(~condition)}"))
out <- dplyr:::replace_with(out, is.na(condition), missing, dplyr:::fmt_args(~missing),
glue::glue("length of {fmt_args(~condition)}"))
out
}
x = 5
if_else(x == 2, min, max)
Error: `true` must be an integer vector, not a primitive function.
這個錯誤是在內部功能的型別檢查的結果check_type中replace_with,看起來像這樣:
if (identical(typeof(x), typeof(template))) {return()}
這里template是out,在 中定義if_else。
- typeof Na_Integer_ 是“整數”
- typeof min 是“內置”
輸出函式min或maxfrom 的解決方案dplyr::if_else是如何強制out成為"builtin"型別,并重新定義dplyr內部函式,例如replace_with,使用另一個因相同原因失敗的子集操作min[]。
也就是說,更改out為內置min函式仍然會引發錯誤:
if_else <- function(...){
...
out <- # if out <- min
...
}
Error in x[i] <- val : object of type 'builtin' is not subsettable
因此,這是預期的行為,但可能object of type 'builtin' is not subsettable不是要顯示的預期錯誤訊息。
uj5u.com熱心網友回復:
如果x始終是標量,則if按照@Gregor Thomas 的回答中所述使用是正確的方法。
另一種選擇是使用switch,這是有道理的,如果您有兩個以上的選項并希望最小化控制流:
x <- 2
min_max <- switch(as.character(x), `2` = min, max)
但是,如果您實際上是在處理一個向量,例如在 {dplyr} 管道中,那么使用character向量而不是函陣列合do.call是一種方法。
這是一個簡短的示例,我們希望根據 中的組使用不同的函式(min或 max):ammtcars
library(dplyr)
mtcars %>%
nest_by(am) %>%
mutate(min_max = if_else(am == 1, "min", "max"),
mpg = summarise(data, x = do.call(min_max, list(mpg)))$x)
#> # A tibble: 2 x 4
#> # Rowwise: am
#> am data min_max mpg
#> <dbl> <list<tibble[,10]>> <chr> <dbl>
#> 1 0 [19 × 10] max 24.4
#> 2 1 [13 × 10] min 15
另一種方法是將每個min,包裝max在list(). 在這種情況下,我們不需要do.call:
library(dplyr)
mtcars %>%
nest_by(am) %>%
mutate(min_max = if_else(am == 1, list(min), list(max)),
mpg = summarise(data, x = min_max(mpg))$x)
#> # A tibble: 2 x 4
#> # Rowwise: am
#> am data min_max mpg
#> <dbl> <list<tibble[,10]>> <list> <dbl>
#> 1 0 [19 × 10] <fn> 24.4
#> 2 1 [13 × 10] <fn> 15
由reprex 包(v0.3.0)于 2021 年 12 月 4 日創建
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/373012.html
上一篇:如何在kableExtra中附加兩個具有相同列數的表?
下一篇:解決模擬問題
