为什么dplyr的过滤器会从因子变量中删除NA值?

时间:2015-10-02 13:45:31

标签: r dplyr subset na

当我使用filter包中的dplyr来删除因子变量的级别时,filter也会删除NA值。这是一个例子:

library(dplyr)
set.seed(919)
(dat <- data.frame(var1 = factor(sample(c(1:3, NA), size = 10, replace = T))))
#    var1
# 1  <NA>
# 2     3
# 3     3
# 4     1
# 5     1
# 6  <NA>
# 7     2
# 8     2
# 9  <NA>
# 10    1

filter(dat, var1 != 1)
#   var1
# 1    3
# 2    3
# 3    2
# 4    2

这似乎并不理想 - 我只想将行放在var1 == 1

看起来这种情况正在发生,因为任何comparison with NA returns NAfilter随后会下降。因此,例如,filter(dat, !(var1 %in% 1))会产生正确的结果。但有没有办法告诉filter不要删除NA值?

3 个答案:

答案 0 :(得分:20)

你可以用这个:

 filter(dat, var1 != 1 | is.na(var1))
  var1
1 <NA>
2    3
3    3
4 <NA>
5    2
6    2
7 <NA>

它不会。

同样只是为了完成,删除NAs是filter的预期行为,如下所示:

test_that("filter discards NA", {
  temp <- data.frame(
    i = 1:5,
    x = c(NA, 1L, 1L, 0L, 0L)
  )
  res <- filter(temp, x == 1)
  expect_equal(nrow(res), 2L)
})

上述测试取自githubfilter测试。

答案 1 :(得分:1)

之前给出的答案很好,但是当您的过滤器语句涉及多个字段的函数时,解决方法可能不会那么好。此外,谁想使用 mapply 非矢量化的 identical。这是另一个使用 coalesce

的更简单的解决方案
filter(dat, coalesce( var1 != 1, TRUE))

答案 2 :(得分:0)

我经常用identical映射mapply ...

(注意:由于R 3.6.0的更改,set.seedsample最终会获得不同的测试数据)

library(dplyr, warn.conflicts = FALSE)
set.seed(919)
(dat <- data.frame(var1 = factor(sample(c(1:3, NA), size = 10, replace = T))))
#>    var1
#> 1     3
#> 2     1
#> 3  <NA>
#> 4     3
#> 5     1
#> 6     3
#> 7     2
#> 8     3
#> 9     2
#> 10    1

filter(dat, var1 != 1)
#>   var1
#> 1    3
#> 2    3
#> 3    3
#> 4    2
#> 5    3
#> 6    2

filter(dat, !mapply(identical, as.numeric(var1), 1))
#>   var1
#> 1    3
#> 2 <NA>
#> 3    3
#> 4    3
#> 5    2
#> 6    3
#> 7    2

它也适用于数字和字符串(可能是更常见的用例)...

library(dplyr, warn.conflicts = FALSE)
set.seed(919)
(dat <- data.frame(var1 = sample(c(1:3, NA), size = 10, replace = T),
                   var2 = letters[sample(c(1:3, NA), size = 10, replace = T)],
                   stringsAsFactors = FALSE))
#>    var1 var2
#> 1     3 <NA>
#> 2     1    a
#> 3    NA    a
#> 4     3    b
#> 5     1    b
#> 6     3 <NA>
#> 7     2    a
#> 8     3    c
#> 9     2 <NA>
#> 10    1    b

filter(dat, !mapply(identical, var1, 1L))
#>   var1 var2
#> 1    3 <NA>
#> 2   NA    a
#> 3    3    b
#> 4    3 <NA>
#> 5    2    a
#> 6    3    c
#> 7    2 <NA>

filter(dat, !mapply(identical, var2, 'a'))
#>   var1 var2
#> 1    3 <NA>
#> 2    3    b
#> 3    1    b
#> 4    3 <NA>
#> 5    3    c
#> 6    2 <NA>
#> 7    1    b