isTRUE和isFALSE在dplyr mutate函数中无法正常工作

时间:2019-08-27 00:10:39

标签: r dplyr mutate

我想检查数据框两列中的值是否不匹配,并使用此信息创建新列。我想使用dplyr::mutate,并且希望能够处理NA值。可以使用以下代码生成一个简单的示例:

library(dplyr)
let <- c("a", "b", NA)
LET <- c("A")
perms <- expand.grid(
    let_2 =  let, 
    LET_2 =  LET, 
    let_1  =  let, 
    LET_1  =  LET, 
    stringsAsFactors = FALSE
) %>% 
    .[ncol(.):1]

> perms
  LET_1 let_1 LET_2 let_2
1     A     a     A     a
2     A     a     A     b
3     A     a     A  <NA>
4     A     b     A     a
5     A     b     A     b
6     A     b     A  <NA>
7     A  <NA>     A     a
8     A  <NA>     A     b
9     A  <NA>     A  <NA>

然后,我要检查1组中的参数是否与2组中的相同参数不匹配。这是所需的输出:

> good_perms
  LET_1 let_1 LET_2 let_2 LET_mismatch let_mismatch
1     A     a     A     a        FALSE        FALSE
2     A     a     A     b        FALSE         TRUE
3     A     a     A  <NA>        FALSE         TRUE
4     A     b     A     a        FALSE         TRUE
5     A     b     A     b        FALSE        FALSE
6     A     b     A  <NA>        FALSE         TRUE
7     A  <NA>     A     a        FALSE         TRUE
8     A  <NA>     A     b        FALSE         TRUE
9     A  <NA>     A  <NA>        FALSE        FALSE

我认为下面的代码应该可以工作,但是它给出以下输出:

good_perms1 <- perms %>% 
    dplyr::mutate(LET_mismatch = !isTRUE(LET_1 == LET_2)) %>% 
    dplyr::mutate(let_mismatch = !isTRUE(let_1 == let_2)) 

> good_perms1
  LET_1 let_1 LET_2 let_2 LET_mismatch let_mismatch
1     A     a     A     a         TRUE         TRUE
2     A     a     A     b         TRUE         TRUE
3     A     a     A  <NA>         TRUE         TRUE
4     A     b     A     a         TRUE         TRUE
5     A     b     A     b         TRUE         TRUE
6     A     b     A  <NA>         TRUE         TRUE
7     A  <NA>     A     a         TRUE         TRUE
8     A  <NA>     A     b         TRUE         TRUE
9     A  <NA>     A  <NA>         TRUE         TRUE

此代码也无法提供所需的输出:

good_perms2 <- perms %>% 
    dplyr::mutate(LET_mismatch = isFALSE(LET_1 == LET_2)) %>% 
    dplyr::mutate(let_mismatch = isFALSE(let_1 == let_2)) 

> good_perms2
  LET_1 let_1 LET_2 let_2 LET_mismatch let_mismatch
1     A     a     A     a        FALSE        FALSE
2     A     a     A     b        FALSE        FALSE
3     A     a     A  <NA>        FALSE        FALSE
4     A     b     A     a        FALSE        FALSE
5     A     b     A     b        FALSE        FALSE
6     A     b     A  <NA>        FALSE        FALSE
7     A  <NA>     A     a        FALSE        FALSE
8     A  <NA>     A     b        FALSE        FALSE
9     A  <NA>     A  <NA>        FALSE        FALSE

如果使用下面的代码,则在定义值时会得到预期的结果,但会得到NA而不是预期的结果:

  • FALSE,其中一个值为NA
  • TRUE,当两个值均为NA
good_perms2 <- perms %>% 
    dplyr::mutate(LET_mismatch = (LET_1 != LET_2)) %>% 
    dplyr::mutate(let_mismatch = (let_1 != let_2)) 

> good_perms2
  LET_1 let_1 LET_2 let_2 LET_mismatch let_mismatch
1     A     a     A     a        FALSE        FALSE
2     A     a     A     b        FALSE         TRUE
3     A     a     A  <NA>        FALSE           NA
4     A     b     A     a        FALSE         TRUE
5     A     b     A     b        FALSE        FALSE
6     A     b     A  <NA>        FALSE           NA
7     A  <NA>     A     a        FALSE           NA
8     A  <NA>     A     b        FALSE           NA
9     A  <NA>     A  <NA>        FALSE           NA

我意识到这里可能存在三个问题,但是第一个是我最困惑的问题:

  1. 为什么dplyr::mutate!isTRUETRUE都将!isTRUE("a" == "a")评估为!isTRUE("a" == "b")?对于isFALSE同样。
  2. 如何(最好在一个函数中)将NA == "a"标识为FALSE,将NA == NA标识为TRUE

NA的问题可能需要单独解决,我现在主要关心的是为什么!isTRUE的行为不符合dplyr::mutate的预期。谢谢!

P.S。 This post谈到了这个问题,但是通过不同的方式解决了。

3 个答案:

答案 0 :(得分:2)

也许用字符“ NA”替换NA,运行代码,然后再用字符NA替换字符“ NA”。

library(dplyr)

good_perms2 <- perms %>% 
  mutate_all(list(~replace(., is.na(.), "NA"))) %>%
  mutate(LET_mismatch = (LET_1 != LET_2)) %>% 
  mutate(let_mismatch = (let_1 != let_2)) %>%
  mutate_all(list(~replace(., . %in% "NA", NA_character_)))
good_perms2 
#   LET_1 let_1 LET_2 let_2 LET_mismatch let_mismatch
# 1     A     a     A     a        FALSE        FALSE
# 2     A     a     A     b        FALSE         TRUE
# 3     A     a     A  <NA>        FALSE         TRUE
# 4     A     b     A     a        FALSE         TRUE
# 5     A     b     A     b        FALSE        FALSE
# 6     A     b     A  <NA>        FALSE         TRUE
# 7     A  <NA>     A     a        FALSE         TRUE
# 8     A  <NA>     A     b        FALSE         TRUE
# 9     A  <NA>     A  <NA>        FALSE        FALSE

答案 1 :(得分:1)

您遇到此问题是因为 isTRUEisFALSE 不是矢量化函数。根据{{​​1}}:

<块引用>

isTRUE(x) 等同于 { is.logical(x) && length(x) == 1 && !is.na(x) && x }; isFALSE() 的定义类似。因此,由于 NA,if(isTRUE(cond)) 可能比 if(cond) 更可取。

了解我刚刚展示的内容后,让我们看看您的问题。

<块引用>
  1. 为什么 !isTRUE("a" == "a") 和 !isTRUE("a" == "b") 的 dplyr::mutate 都将 !isTRUE 评估为 TRUE?与 isFALSE 类似。
?isTRUE

这里一切正常。现在,让我们对非标量对象进行同样的尝试。

x <- "a" == "a" # TRUE
y <- "a" == "b" # FALSE
!isTRUE(x)
#> [1] FALSE
!isTRUE(y)
#> [1] TRUE
!(is.logical(x) && length(x) == 1 && !is.na(x) && x)
#> [1] FALSE
!(is.logical(y) && length(y) == 1 && !is.na(y) && y)
#> [1] TRUE

如您所见,let_1 <- c("a", "a", "a", "b", "b", "b", NA, NA, NA) let_2 <- c("a", "b", NA, "a", "b", NA, "a", "b", NA) let_1 == let_2 #> [1] TRUE FALSE NA FALSE TRUE NA NA NA NA !isTRUE(let_1 == let_2) #> TRUE x <- (let_1 == let_2) !(is.logical(x) && length(x) == 1 && !is.na(x) && x) #> TRUE 返回长度为 1 的对象。使用 isTRUE 时,函数会将值回收到所有元素,这就是所有 mutate 等于 let_mismatch 的原因。

<块引用>
  1. 我如何(最好在一个函数中)将 NA == "a" 识别为 FALSE,将 NA == NA 识别为 TRUE?

@www 已经展示了解决这个问题的方法。更好的方法是使用矢量化 if-else,例如 TRUE

您可以使用函数来执行此操作,但这不是最好的方法(下面的示例)。如果您想直接分配逻辑表达式(也不是解决您的问题的最佳方法),您还可以创建一个处理表达式的函数。

dplyr::case_when()

这是使用您展示的示例的 library(dplyr) foo <- function(x, y) { case_when( is.na(x) & !is.na(y) ~ FALSE, is.na(x) & is.na(y) ~ TRUE) } foo(NA, "a") #> [1] FALSE foo(NA, NA) #> [1] TRUE 解决方案。

case_when()

答案 2 :(得分:1)

添加rowwise()

good_perms1 <- perms %>% rowwise() %>%
    dplyr::mutate(LET_mismatch = !isTRUE(LET_1 == LET_2)) %>% 
    dplyr::mutate(let_mismatch = !isTRUE(let_1 == let_2))