是否可以使用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))
答案 0 :(得分:149)
试试这个:
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和评论。
答案 1 :(得分:26)
这对我有用:
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
答案 2 :(得分:13)
这是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
答案 3 :(得分:10)
这是一个简短的函数,它允许您指定不应具有任何NA值的列(基本上dplyr::select
可以理解的所有内容)(以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 is now part of 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
答案 4 :(得分:6)
试试这个
df[complete.cases(df),] #output to console
或者甚至是这个
df.complete <- df[complete.cases(df),] #assign to a new data.frame
以上命令负责检查所有列的完整性(变量) 在你的data.frame中。
答案 5 :(得分: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
变体中最快的方法(使用@MihaTrošt微基准测试进行测试)。
答案 6 :(得分:1)
dplyr >= 1.0.4
if_any
和 if_all
在较新版本的 dplyr
中可用,以在 across
函数中应用类似 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
有关这些函数的更多信息,请参阅此 link。