【问题标题】:isTRUE and isFALSE not working as expected in dplyr mutate functionisTRUE 和 isFALSE 在 dplyr mutate 函数中没有按预期工作
【发布时间】:2019-12-31 03:16:26
【问题描述】:

我想检查数据框两列中的值是否不匹配,并使用此信息创建一个新列。我想使用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!isTRUE("a" == "a")!isTRUE("a" == "b") 都将!isTRUE 评估为TRUEisFALSE 也是如此。
  2. 我如何(最好是在一个函数中)将NA == "a" 识别为FALSE,将NA == NA 识别为TRUE

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

附: This post 涉及到这个问题,但是通过不同的方式解决了。

【问题讨论】:

  • 先看看isTRUE(perms$let_1 == perms$let_2)给出了什么。 isTRUE 没有被它的外观矢量化。来自?isTRUE "'isTRUE(x)' 是 'identical(TRUE, x)' 的缩写,当且仅当 'x' 是长度为一的逻辑向量时才为真"
  • 我也无法复制您的 1. 查询 - !isTRUE("a" == "a") 提供 FALSE!isTRUE("a" == "b") 提供 TRUE
  • @thelatemail,对于你的第二点,我应该说“来自dplyr::mutate”。对于您的第一点,我曾认为mutate 评估!isTRUE(perms$let_1[1] == perms$let_2[1] 然后评估!isTRUE(perms$let_1[2] == perms$let_2[1],但您让我意识到mutate 评估!isTRUE(perms$let_1 == perms$let_2。我需要编写isTRUE 的矢量化版本来处理我对NA 的特定标准。谢谢。

标签: r dplyr


【解决方案1】:

也许将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

【讨论】:

  • NA 转换为"NA" 将比我要编写的复杂的is.na 函数容易得多。谢谢!
  • mutate_all(~replace(., is.na(.), "NA")) 似乎有效。是否有需要mutate_all(list(~replace(., is.na(.), "NA"))) 的用例?另外,我以前从未见过NA_character_。那将很有用。谢谢!
  • 可以创建函数f1 &lt;- function(x, y) replace(x, is.na(x), "999") != replace(y, is.na(y), "999"); perms %&gt;% mutate(LET_mismatch = f1(LET_1, LET_2), let_mismatch = f1(let_1, let_2))
【解决方案2】:

您遇到此问题是因为 isTRUEisFALSE 不是矢量化函数。据?isTRUE

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

知道我刚才在上面展示的内容,让我们看看你的问题。

  1. 为什么 dplyr::mutate 对于 !isTRUE("a" == "a") 和 !isTRUE("a" == "b") 都将 !isTRUE 评估为 TRUE? isFALSE 也是如此。
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

如您所见,isTRUE 返回一个长度为 1 的对象。使用mutate时,该函数将值回收到所有元素,这就是为什么所有let_mismatch等于TRUE

  1. 如何(理想情况下在一个函数中)将 NA == "a" 识别为 FALSE 并将 NA == NA 识别为 TRUE?

@www 已经展示了解决此问题的方法。更好的方法是使用矢量化 if-else,例如 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() 解决方案。

library(dplyr)

good_perms1 <- perms %>% 
    mutate(LET_mismatch = case_when(
        LET_1 == LET_2 ~ FALSE,
        is.na(LET_1) & is.na(LET_2) ~ FALSE,
        TRUE ~ TRUE),
    let_mismatch = case_when(
        let_1 == let_2 ~ FALSE,
        is.na(let_1) & is.na(let_2) ~ FALSE,
        TRUE ~ TRUE))

good_perms1
#>   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

【讨论】:

    【解决方案3】:

    添加rowwise()

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-12-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多