【问题标题】:Why does dplyr's filter drop NA values from a factor variable?为什么 dplyr 从因子变量中过滤 dropNA 值?
【发布时间】:2015-12-30 17:56:52
【问题描述】:

当我使用 dplyr 包中的 filter 删除因子变量的级别时,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 NA,然后filter 丢弃。因此,例如,filter(dat, !(var1 %in% 1)) 会产生正确的结果。但是有没有办法告诉filter 不要删除NA 值?

【问题讨论】:

  • @akrun 出于某种原因,我没有收到此通知:P。好吧,我认为 OP 已经知道这一点,正如他提到的 filter(dat, !(var1 %in% 1)) 相似,但我认为这是使用 dplyr::filter 的唯一方法。
  • 我认为没有办法明确告诉 filter 不要删除 NA 值,但一般来说,逻辑 NA 查询可以使用基本 %in% 运算符直观地处理,它是否定,定义为%ni% &lt;- Negate('%in%')。因此,您可以使用filter(dat, var1 %ni% 1),它会起作用。见stackoverflow.com/a/11303276/4269699stackoverflow.com/a/27015823/4269699
  • 是的,我确实知道这种方法和@LyzanderR 用于回答的方法。看起来过滤器没有“keep NA”的明确选项,所以这些解决方法会很好。感谢您的帮助。
  • 啊,这发生在我身上,我疯了,试图理解为什么我丢失了这么多数据。同意这似乎并不理想......

标签: r dplyr subset na


【解决方案1】:

你可以用这个:

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

它不会。

也只是为了完成,删除 NA 是 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)
})

上述测试取自 filter 的测试,来自 github

【讨论】:

  • 冒险进入基于意见的领域,您知道为什么选择这种方法吗?这种行为出乎我的意料(我今天被它咬了)。
  • @Heisenberg 根据 Hadley 的说法,我假设大多数人在过滤时不希望得到任何 NA。但这是开发人员/维护人员(即 Hadley)的问题。
【解决方案2】:

前面给出的答案都很好,但是当你的过滤语句涉及多个字段的函数时,变通的方法可能就不那么好了。另外,谁想使用mapply 非矢量化identical。这是使用coalesce的另一个更简单的解决方案

filter(dat, coalesce( var1 != 1, TRUE))

【讨论】:

    【解决方案3】:

    我经常将identicalmapply 映射...

    (注意:我相信由于 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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-04-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多