Ответ 1
Попробуйте следующее:
df %>% na.omit
или это:
df %>% filter(complete.cases(.))
ADDED Обновлены, чтобы отразить последнюю версию dplyr и комментарии.
Можно ли отфильтровать data.frame для полных случаев с использованием dplyr? 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))
Попробуйте следующее:
df %>% na.omit
или это:
df %>% filter(complete.cases(.))
ADDED Обновлены, чтобы отразить последнюю версию dplyr и комментарии.
Это работает для меня:
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 (смоделированных после 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
попробуйте это
df[complete.cases(df),] #output to console
ИЛИ даже это
df.complete <- df[complete.cases(df),] #assign to a new data.frame
Вышеупомянутые команды заботятся о проверке полноты для всех столбцов (переменных) в вашем файле data.frame.
Вот некоторые результаты теста для ответа Гротендика. 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
Только для полноты, 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).