使用dplyr筛选data.frame中的完整事例(按事例删除)

使用dplyr筛选data.frame中的完整事例(按事例删除),r,dplyr,magrittr,R,Dplyr,Magrittr,是否可以使用dplyr过滤data.frame中的完整案例?当然,用所有变量的列表来完成.cases是有效的。但是,当有很多变量时,这是冗长的;当变量名未知时,这是不可能的,例如在处理任何data.frame的函数中 library(dplyr) df = data.frame( x1 = c(1,2,3,NA), x2 = c(1,2,NA,5) ) df %.% filter(complete.cases(x1,x2)) 试试这个 df[complete.cases(

是否可以使用dplyr过滤data.frame中的完整案例?当然,用所有变量的列表来完成.cases是有效的。但是,当有很多变量时,这是冗长的;当变量名未知时,这是不可能的,例如在处理任何data.frame的函数中

library(dplyr)
df = data.frame(
    x1 = c(1,2,3,NA),
    x2 = c(1,2,NA,5)
)

df %.%
  filter(complete.cases(x1,x2))
试试这个

df[complete.cases(df),] #output to console
甚至这个

df.complete <- df[complete.cases(df),] #assign to a new data.frame
上述命令负责检查所有变量列的完整性 在data.frame中。

尝试以下操作:

library(dplyr)
df = data.frame(
    x1 = c(1,2,3,NA),
    x2 = c(1,2,NA,5)
)

df %.%
  filter(complete.cases(x1,x2))
df %>% na.omit
或者这个:

df %>% filter(complete.cases(.))
library(tidyr)
df %>% drop_na
或者这个:

df %>% filter(complete.cases(.))
library(tidyr)
df %>% drop_na
如果要基于一个变量的缺失进行筛选,请使用条件:

df %>% filter(!is.na(x1))

其他答案表明,na.omit上面的解决方案的速度要慢得多,但这必须与它返回na.action属性中被省略行的行索引这一事实相平衡,而上面的其他解决方案则没有

str(df %>% na.omit)
## 'data.frame':   2 obs. of  2 variables:
##  $ x1: num  1 2
##  $ x2: num  1 2
##  - attr(*, "na.action")= 'omit' Named int  3 4
##    ..- attr(*, "names")= chr  "3" "4"
已添加更新,以反映dplyr的最新版本和评论


添加了更新以反映最新版本的tidyr和评论。

以下是Grothendieck回复的一些基准测试结果。na.omit需要的时间是其他两种解决方案的20倍。我认为如果dplyr有一个函数来实现这一点会很好,也许可以作为过滤器的一部分

library('rbenchmark')
library('dplyr')

n = 5e6
n.na = 100000
df = data.frame(
    x1 = sample(1:10, n, replace=TRUE),
    x2 = sample(1:10, n, replace=TRUE)
)
df$x1[sample(1:n, n.na)] = NA
df$x2[sample(1:n, n.na)] = NA


benchmark(
    df %>% filter(complete.cases(x1,x2)),
    df %>% na.omit(),
    df %>% (function(x) filter(x, complete.cases(x)))()
    , replications=50)

#                                                  test replications elapsed relative
# 3 df %.% (function(x) filter(x, complete.cases(x)))()           50   5.422    1.000
# 1               df %.% filter(complete.cases(x1, x2))           50   6.262    1.155
# 2                                    df %.% na.omit()           50 109.618   20.217
这对我很有用:

df %>%
  filter(complete.cases(df))    
或者更一般一点:

library(dplyr) # 0.4
df %>% filter(complete.cases(.))
这样做的好处是,在将数据传递给过滤器之前,可以在链中修改数据

另一个包含更多列的基准:

set.seed(123)
x <- sample(1e5,1e5*26, replace = TRUE)
x[sample(seq_along(x), 1e3)] <- NA
df <- as.data.frame(matrix(x, ncol = 26))
library(microbenchmark)
microbenchmark(
  na.omit = {df %>% na.omit},
  filter.anonymous = {df %>% (function(x) filter(x, complete.cases(x)))},
  rowSums = {df %>% filter(rowSums(is.na(.)) == 0L)},
  filter = {df %>% filter(complete.cases(.))},
  times = 20L,
  unit = "relative")

#Unit: relative
#             expr       min        lq    median         uq       max neval
 #         na.omit 12.252048 11.248707 11.327005 11.0623422 12.823233    20
 #filter.anonymous  1.149305  1.022891  1.013779  0.9948659  4.668691    20
 #         rowSums  2.281002  2.377807  2.420615  2.3467519  5.223077    20
 #          filter  1.000000  1.000000  1.000000  1.0000000  1.000000    20

这是一个简短的函数,它允许您指定dplyr::select可以理解的所有列,这些列不应具有任何模仿熊猫的NA值:


为了完整起见,dplyr::filter可以完全避免,但仍然可以使用magrittr:extract别名[:

额外的好处是速度,这是使用@Miha Trošt微基准测试的过滤器和na.omit变体中最快的方法。

dplyr>=1.0.4

在较新版本的dplyr中,if_any和if_all可用于在筛选器函数中应用类似语法。如果数据帧中有其他变量不属于您认为完整的情况,这可能会很有用。例如,如果您只希望在以x开头的列中不缺少行:

library(dplyr)
df = data.frame(
  x1 = c(1,2,3,NA),
  x2 = c(1,2,NA,5),
  y = c(NA, "A", "B", "C")
)

df %>% 
  dplyr::filter(if_all(starts_with("x"), ~!is.na(.)))

  x1 x2    y
1  1  1 <NA>
2  2  2    A

有关这些函数的更多信息,请参见此。

complete.cases不只是接受向量。它还需要整个数据帧。但这不能作为dplyr的过滤函数的一部分。我想我还不够清楚,并更新了我的问题。如果你能确切地演示它如何不与dplyr一起工作,那会有所帮助,但当我尝试使用它时h filter,它工作得很好。谢谢。虽然问题更新了,但我想我还不够清楚。我知道complete.casesdf,但我想使用dplyr作为筛选函数的一部分。这将允许在dplyr链等中进行整洁的集成。请通过@G.GrothendieckIn dplyr:::do.data.frame语句env$检查答案。抱歉,必须输入d注释放错了地方。刚回来回答,看到了你有用的答案!谢谢!我添加了一些基准测试结果。na.omit执行得很差,但这个很快。现在也可以使用:df%>%filtercomplete.cases..不确定dplyr中最近的更改是否使这成为可能。正如@jan katins指出的,调用了Tidyverse函数drop_na,所以你现在可以做:df%>%drop_na。我在complete.cases中更新了你的答案,并添加了基准-希望你不介意:-:我不介意。谢谢。我发现df%>%slicewhichcomplete.cases。执行速度比上述基准中的过滤方法快约20%。值得注意的是,如果你在dplyr管道中与oth一起使用此过滤器er dplyr命令,如group_by,在尝试对complete.cases进行筛选之前,您需要添加%>%data.frame%>%,因为它对TIBLES或分组TIBLES或其他东西不起作用。或者至少,这是我的经验。当我使用Miha Trošt的数据进行基准测试时,我发现使用extract的速度要慢十倍han filter。但是,当我用df创建一个更小的数据帧时,你是正确的。看起来magrittr::extract是最快的方法,只有当n能够添加0.5这样的截止值并按列处理时才更有用?案例:消除50%以上缺失数据的变量。例如:数据[,-whichmeansis.nadata>0.5]如果能用tidyr做到这一点就太好了。@Monduiz这意味着在变量有大量NA的地方添加更多数据可能会在管道的下一步失败,因为现在缺少所需的变量…对,这是有意义的。
library(dplyr)
df = data.frame(
  x1 = c(1,2,3,NA),
  x2 = c(1,2,NA,5),
  y = c(NA, "A", "B", "C")
)

df %>% 
  dplyr::filter(if_all(starts_with("x"), ~!is.na(.)))

  x1 x2    y
1  1  1 <NA>
2  2  2    A