112

是否可以使用 dplyr 过滤完整案例的 data.frame?complete.cases当然,所有变量的列表都有效。但这是a)当有很多变量时很冗长,而b)当变量名称未知时(例如在处理任何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))
4

7 回答 7

208

试试这个:

df %>% na.omit

或这个:

df %>% filter(complete.cases(.))

或这个:

library(tidyr)
df %>% drop_na

如果要根据一个变量的缺失进行过滤,请使用条件:

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

或者

df %>% drop_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 和评论

于 2014-03-12T16:51:08.900 回答
27

这对我有用:

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
于 2014-05-13T11:04:43.687 回答
17

以下是格洛腾迪克回复的一些基准测试结果。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
于 2014-03-13T21:35:39.697 回答
13

dplyr::select这是一个简短的函数,可让您指定不应具有任何 NA 值的列(基本上是所有可以理解的)(以 pandas df.dropna()为模型):

drop_na <- function(data, ...){
    if (missing(...)){
        f = complete.cases(data)
    } else {
        f <- complete.cases(select_(data, .dots = lazyeval::lazy_dots(...)))
    }
    filter(data, f)
}

[ drop_na 现在是 tidyr的一部分:上面可以替换为library("tidyr")]

例子:

library("dplyr")
df <- data.frame(a=c(1,2,3,4,NA), b=c(NA,1,2,3,4), ac=c(1,2,NA,3,4))
df %>% drop_na(a,b)
df %>% drop_na(starts_with("a"))
df %>% drop_na() # drops all rows with NAs
于 2016-05-04T14:47:39.913 回答
7

试试这个

df[complete.cases(df),] #output to console

或者甚至这个

df.complete <- df[complete.cases(df),] #assign to a new data.frame

上述命令负责检查 data.frame 中所有列(变量)的完整性。

于 2014-03-12T13:59:22.117 回答
3

只是为了完整起见,dplyr::filter可以完全避免,但仍然可以通过使用magrittr:extract(的别名[)来组合链:

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

df %>%
  extract(complete.cases(.), )

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

于 2016-06-23T08:09:56.897 回答
1

dplyr >= 1.0.4

if_any并且if_all在较新版本的dplyrto apply across-like 语法中可用filter。如果您的数据框中有其他变量不是您认为完整案例的一部分,这可能会很有用。例如,如果您只想要以“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

有关这些功能的更多信息,请参阅此链接

于 2021-02-08T21:48:52.927 回答