`dplyr::case_when` Evaluation error: object 'x' not found

`dplyr::case_when` Evaluation error: object 'x' not found

有谁知道为什么 dplyr::case_when() 会在下面的代码中产生错误?

tibble(tmp1 = sample(c(T, F), size = 32, replace = T),
       tmp2 = sample(c(T, F), size = 32, replace = T),
       tmp3 = sample(c(T, F), size = 32, replace = T)) %>%
  mutate(tmp = apply(cbind(tmp1, tmp2, tmp3), 1, function(x) {
    case_when(
      all(x == F) ~ "N",
      any(x == T) ~ "Y"
    )
  }))

Error in mutate_impl(.data, dots) : 
  Evaluation error: object 'x' not found.

我在 Ubuntu 16.04 上使用 R 3.4.3 和 dplyr 0.7.4。

错误消息非常混乱,因为下面的代码工作正常,这表明 x 没有丢失:

tibble(tmp1 = sample(c(T, F), size = 32, replace = T),
       tmp2 = sample(c(T, F), size = 32, replace = T),
       tmp3 = sample(c(T, F), size = 32, replace = T)) %>%
  mutate(tmp = apply(cbind(tmp1, tmp2, tmp3), 1, function(x) {
    if (all(x == F)) {
      "N"
    } else if(any(x == T)) {
      "Y"
    }
  }))

仅供参考,以下代码也可以正常工作:

cbind(tmp1 = sample(c(T, F), size = 32, replace = T),
      tmp2 = sample(c(T, F), size = 32, replace = T),
      tmp3 = sample(c(T, F), size = 32, replace = T)) %>%
  apply(1, function(x) {
    case_when(
      all(x == F) ~ "N",
      any(x == T) ~ "Y"
    )
  })

问题是 case_when 没有执行 row-wise 操作。但是,我们可以通过使用 rowSums(执行 row-wise 操作)和 case_when.

来简化代码
library(dplyr)

set.seed(151)

tibble(tmp1 = sample(c(T, F), size = 32, replace = T),
       tmp2 = sample(c(T, F), size = 32, replace = T),
       tmp3 = sample(c(T, F), size = 32, replace = T)) %>%
  mutate(tmp = case_when(
      rowSums(.) == 0   ~"N",
      rowSums(.) > 0    ~"Y" 
    ))

# # A tibble: 32 x 4
#   tmp1  tmp2  tmp3  tmp  
#   <lgl> <lgl> <lgl> <chr>
#  1 TRUE  TRUE  FALSE Y    
#  2 FALSE FALSE TRUE  Y    
#  3 FALSE FALSE TRUE  Y    
#  4 FALSE FALSE TRUE  Y    
#  5 TRUE  FALSE FALSE Y    
#  6 FALSE FALSE FALSE N    
#  7 TRUE  FALSE FALSE Y    
#  8 FALSE TRUE  FALSE Y    
#  9 TRUE  TRUE  FALSE Y    
# 10 FALSE FALSE TRUE  Y    
# # ... with 22 more rows

或者只有两个条件,rowSumsifelse应该没问题。

set.seed(151)

tibble(tmp1 = sample(c(T, F), size = 32, replace = T),
       tmp2 = sample(c(T, F), size = 32, replace = T),
       tmp3 = sample(c(T, F), size = 32, replace = T)) %>%
  mutate(tmp = ifelse(rowSums(.) == 0, "N", "Y"))
# # A tibble: 32 x 4
#   tmp1  tmp2  tmp3  tmp  
#   <lgl> <lgl> <lgl> <chr>
#  1 TRUE  TRUE  FALSE Y    
#  2 FALSE FALSE TRUE  Y    
#  3 FALSE FALSE TRUE  Y    
#  4 FALSE FALSE TRUE  Y    
#  5 TRUE  FALSE FALSE Y    
#  6 FALSE FALSE FALSE N    
#  7 TRUE  FALSE FALSE Y    
#  8 FALSE TRUE  FALSE Y    
#  9 TRUE  TRUE  FALSE Y    
# 10 FALSE FALSE TRUE  Y    
# # ... with 22 more rows

使用 Reduce 和逻辑或如何?

set.seed(151);
tibble(tmp1 = sample(c(T, F), size = 32, replace = T),
       tmp2 = sample(c(T, F), size = 32, replace = T),
       tmp3 = sample(c(T, F), size = 32, replace = T)) %>%
    mutate(tmp = Reduce(`|`, list(tmp1, tmp2, tmp3)))
## A tibble: 32 x 4
#   tmp1  tmp2  tmp3  tmp
#   <lgl> <lgl> <lgl> <lgl>
# 1 TRUE  TRUE  FALSE TRUE
# 2 FALSE FALSE TRUE  TRUE
# 3 FALSE FALSE TRUE  TRUE
# 4 FALSE FALSE TRUE  TRUE
# 5 TRUE  FALSE FALSE TRUE
# 6 FALSE FALSE FALSE FALSE
# 7 TRUE  FALSE FALSE TRUE
# 8 FALSE TRUE  FALSE TRUE
# 9 TRUE  TRUE  FALSE TRUE
#10 FALSE FALSE TRUE  TRUE
## ... with 22 more rows

事实证明,这是一个错误,可能与混合评估器有关:https://github.com/tidyverse/dplyr/issues/3422