фильтр для полных случаев в данных.кадр с использованием dplyr (удаление по регистру)
можно ли фильтровать данные.рамка для полных случаев с использованием dplyr? complete.cases
со списком всех переменных работает, конечно. Но это а) многословно, когда есть много переменных и Б) невозможно, когда имена переменных неизвестны (например, в функции, которая обрабатывает любые данные.рамка.)
library(dplyr)
df = data.frame(
x1 = c(1,2,3,NA),
x2 = c(1,2,NA,5)
)
df %.%
filter(complete.cases(x1,x2))
6 ответов:
попробуйте это:
df %>% na.omit
или такой:
df %>% filter(complete.cases(.))
или такой:
library(tidyr) df %>% drop_na
если вы хотите фильтровать на основе пропускания одной переменной, используйте условное:
df %>% filter(!is.na(x1))
или
df %>% drop_na(x1)
другие ответы указывают на то, что из решений выше
na.omit
намного медленнее, но это должно быть сбалансировано с тем фактом, что он возвращает и индексы строк пропущенных строк как в то время как другие решения выше не.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 и комментарии.
это работает для меня:
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
вот некоторые результаты тестов для ответа Гротендика. не доступно.опустить () занимает в 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::select
может понять), который не должен иметь никаких значений NA (смоделированных после панд 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
вышеуказанные команды заботятся о проверке полноты для всех столбцов (переменная) в ваших данных.рамка.
просто для полноты картины,
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 microbenchmarks).