【问题标题】:Does dplyr::if_else evaluate both TRUE and FALSE at the same time? [duplicate]dplyr::if_else 是否同时评估 TRUE 和 FALSE? [复制]
【发布时间】:2019-12-23 00:11:48
【问题描述】:

考虑以下示例:

library(dplyr)

# sample data 
set.seed(1)
mydf <- data.frame(value = as.logical(sample(0:1, 15, replace = TRUE)), group = rep(letters[1:3],each = 5), index = 1:5)

# finds either index of first "TRUE" value by group, or the last value. 
# works with base::ifelse
mydf %>% group_by(group) %>% mutate(max_value = ifelse(all(!value), max(index), index[min(which(value))]))
#> # A tibble: 15 x 4
#> # Groups:   group [3]
#>    value group index   max_value
#>    <lgl> <fct> <int>      <int>
#>  1 FALSE a         1          2
#>  2 TRUE  a         2          2
#>  3 FALSE a         3          2
#>  4 FALSE a         4          2
#>  5 TRUE  a         5          2
#>  6 FALSE b         1          4
#>  7 FALSE b         2          4
#>  8 FALSE b         3          4
#>  9 TRUE  b         4          4
#> 10 TRUE  b         5          4
#> 11 FALSE c         1          5
#> 12 FALSE c         2          5
#> 13 FALSE c         3          5
#> 14 FALSE c         4          5
#> 15 FALSE c         5          5

# the same gives a warning with dplyr::if_else
mydf %>% group_by(group) %>% mutate(max_value = if_else(all(!value), max(index), index[min(which(value))]))

#> Warning in min(which(value)): no non-missing arguments to min; returning Inf

#> # A tibble: 15 x 4
#> # Groups:   group [3]
#>    value group index  max_value
#>    <lgl> <fct> <int>      <int>
#>  1 FALSE a         1          2
#>  2 TRUE  a         2          2
#>  3 FALSE a         3          2
#>  4 FALSE a         4          2
#>  5 TRUE  a         5          2
#>  6 FALSE b         1          4
#>  7 FALSE b         2          4
#>  8 FALSE b         3          4
#>  9 TRUE  b         4          4
#> 10 TRUE  b         5          4
#> 11 FALSE c         1          5
#> 12 FALSE c         2          5
#> 13 FALSE c         3          5
#> 14 FALSE c         4          5
#> 15 FALSE c         5          5

正如代码中所述 - dplyr::if_else 确实会导致警告

警告 min(which(value)): no non-missing arguments to min;返回Inf

删除“all FALSE”组 c - 不再有警告:

mydf_allTRUE <- mydf
mydf_allTRUE[14, 'value'] <- TRUE

mydf_allTRUE %>% group_by(group) %>% mutate(max_value = if_else(all(!value), max(index), index[min(which(value))]))
#> # A tibble: 15 x 4
#> # Groups:   group [3]
#>    value group index max_value
#>    <lgl> <fct> <int>     <int>
#>  1 FALSE a         1         2
#>  2 TRUE  a         2         2
#>  3 FALSE a         3         2
#>  4 FALSE a         4         2
#>  5 TRUE  a         5         2
#>  6 FALSE b         1         4
#>  7 FALSE b         2         4
#>  8 FALSE b         3         4
#>  9 TRUE  b         4         4
#> 10 TRUE  b         5         4
#> 11 FALSE c         1         4
#> 12 FALSE c         2         4
#> 13 FALSE c         3         4
#> 14 TRUE  c         4         4
#> 15 FALSE c         5         4

reprex package (v0.3.0) 于 2019 年 12 月 22 日创建

让我感到困惑的是(我相信)我构造了TRUE 部分,而FALSE 部分(index[min(which(value))]必须包含一个值。为什么这会发出警告? 这是有问题的,因为我有几千组的数据,其中大多数都在“FALSE”位中,并且警告使计算变得非常缓慢。

我很高兴使用base::ifelse,但我只是想知道dplyr::if_else 是如何评估真假两面的,这是同时进行的吗?

【问题讨论】:

    标签: r dplyr


    【解决方案1】:

    问题是因为我们正在检查有返回NULL withwhich(value)`的组的情况

    min(NULL)
    #[1] Inf
    

    警告信息:在 min(NULL) 中:min 没有非缺失参数; 返回Inf


    一种选择是通过使用[1] 索引来使which 输出受控以返回NA

    mydf %>%
       group_by(group) %>%
       mutate(max_value = if_else(all(!value), max(index), index[which(value)[1]]))
    # A tibble: 15 x 4
    # Groups:   group [3]
    #   value group index max_value
    #   <lgl> <fct> <int>     <int>
    # 1 FALSE a         1         2
    # 2 TRUE  a         2         2
    # 3 FALSE a         3         2
    # 4 FALSE a         4         2
    # 5 TRUE  a         5         2
    # 6 FALSE b         1         4
    # 7 FALSE b         2         4
    # 8 FALSE b         3         4
    # 9 TRUE  b         4         4
    #10 TRUE  b         5         4
    #11 FALSE c         1         5
    #12 FALSE c         2         5
    #13 FALSE c         3         5
    #14 FALSE c         4         5
    #15 FALSE c         5         5
    

    另外,在这种情况下,由于我们返回单个元素,if/else 会更合适

    mydf %>%
        group_by(group) %>%
        mutate(max_value = if(all(!value)) max(index) else index[which(value)[1]])
    # A tibble: 15 x 4
    # Groups:   group [3]
    #   value group index max_value
    #   <lgl> <fct> <int>     <int>
    # 1 FALSE a         1         2
    # 2 TRUE  a         2         2
    # 3 FALSE a         3         2
    # 4 FALSE a         4         2
    # 5 TRUE  a         5         2
    # 6 FALSE b         1         4
    # 7 FALSE b         2         4
    # 8 FALSE b         3         4
    # 9 TRUE  b         4         4
    #10 TRUE  b         5         4
    #11 FALSE c         1         5
    #12 FALSE c         2         5
    #13 FALSE c         3         5
    #14 FALSE c         4         5
    #15 FALSE c         5         5
    

    【讨论】:

    • 那么,您是说dplyr::if_else 确实似乎同时测试了 TRUE 和 FALSE?
    • 感谢索引的想法,非常聪明
    • @Tjebo if_else 带有类型等附加检查。在您的情况下,不需要ifelse/if_else,因为它返回单个输出
    • 这确实是非常正确的。它实际上对我很有启发性,因为直到现在我还没有完全掌握 ifelse/if_else 和 if/else 之间的本质区别。很有意义。谢谢
    猜你喜欢
    • 1970-01-01
    • 2023-03-29
    • 2015-03-15
    • 1970-01-01
    • 1970-01-01
    • 2019-04-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多