数据框列全部为NA时过滤,但有些列为NA时保留。

4

我希望能够从数据框中删除所有列都为 NA 的行。但我想保留那些有一些值为 NA 的行。

我知道如何使用基本的 R 实现这个功能,但我正在尝试使用 tidyverse 来解决它。我正在尝试使用 across 运算符。

library(tidyverse)

teste <- data.frame(a = c(1,NA,3, NA), b = c(NA, NA, 3, 4), c = c(1, NA, 3, 4))

teste
#>    a  b  c
#> 1  1 NA  1
#> 2 NA NA NA
#> 3  3  3  3
#> 4 NA  4  4
# I whant to remove rows where all values are NA
# that is, remove only line 2

# here I can get the lines with all values NA
teste %>%
  filter(across(a:c, is.na))
#>    a  b  c
#> 1 NA NA NA

# If I negate the filter, it does not work
# the last line (NA, 4, 4) is missing
teste %>%
  filter(!across(a:c, is.na))
#>   a  b c
#> 1 1 NA 1
#> 2 3  3 3

# This is what I'm expecting
# a  b  c
# 1 NA  1
# 3  3  3
# NA  4  4

# Using base I can do this with
teste[apply(teste, 1, function(x) sum(is.na(x))) < 3,]
#>    a  b c
#> 1  1 NA 1
#> 3  3  3 3
#> 4 NA  4 4

我该如何使用 tidyverse 呢? reprex包 (v0.3.0) 于2020-08-18创建

这个回答解决了你的问题吗?在数据框中删除所有或部分NAs(缺失值)的行 - Duck
它确实帮助找到了使用Base R的方法。但是我在使用filter时遇到了困难。也许我没有完全掌握那些答案中的所有信息。无论如何,我已经在这里接受了一个答案,但最终在我的代码中使用了R base... - Daniel
3个回答

3
我们可以使用 base R
teste[rowSums(!is.na(teste)) >0,]
#   a  b c
#1  1 NA 1
#3  3  3 3
#4 NA  4 4

或者使用applyany

teste[apply(!is.na(teste), 1, any),]

这也可以在filter内使用。

teste %>%
      filter(rowSums(!is.na(.)) >0)

或者使用dplyr中的c_across,我们可以直接删除所有行中包含all NA的行。

library(dplyr)
teste %>% 
    rowwise %>% 
    filter(!all(is.na(c_across(everything()))))
# A tibble: 3 x 3
# Rowwise: 
#      a     b     c
#  <dbl> <dbl> <dbl>
#1     1    NA     1
#2     3     3     3
#3    NA     4     4

注意: filter_all 将被废弃


我在 Twitter 上看到了一个类似的问题,并给出了类似于 rowSums 解决方案的东西。然而,我一直在想,对于非常大的数据集,这种解决方案会有多快,因为首先在整个数据集上使用 is.na 进行检查似乎太“昂贵”了。 - NelsonGon
1
如果内存不受限制,那么速度应该很快。否则,对于非常大的数据集,它取决于列数等因素。如果输入数据集是fst格式,使用tidyft可能会稍微快一些。@NelsonGon - akrun

2

以前在 dplyr 中,您可以使用 filter_all(针对所有列)/filter_at(针对特定列),它们都有 any_vars

library(dplyr)

teste %>% filter_all(any_vars(!is.na(.)))

然而,across 没有直接替代 any_vars 的方法,所以您可以使用以下方式与 Reduce 一起使用:

teste %>% filter(Reduce(`|`, across(.fns = Negate(is.na))))
#   a  b c
#1  1 NA 1
#2  3  3 3
#3 NA  4 4

2
使用data.table,您可以产生相同的结果。
teste2 <- teste[-which(is.na(teste$a)&is.na(teste$b)&is.na(teste$c)),]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接