filtruj kompletne przypadki w danych.frame using dplyr (case-wise deletion)

Czy możliwe jest filtrowanie danych.ramka do kompletnych przypadków za pomocą dplyr? complete.cases z listą wszystkich zmiennych działa, oczywiście. Ale to jest a) verbose, gdy istnieje wiele zmiennych i B) niemożliwe, gdy nazwy zmiennych nie są znane (np. w funkcji, która przetwarza dowolne dane.ramka).

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

df %.%
  filter(complete.cases(x1,x2))
Author: mbask, 2014-03-12

6 answers

Spróbuj tego:

df %>% na.omit

Lub to:

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

Lub to:

library(tidyr)
df %>% drop_na

Jeśli chcesz filtrować na podstawie missingness jednej zmiennej, użyj warunkowego:

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

Lub

df %>% drop_na(x1)

Inne odpowiedzi wskazują, że z powyższych rozwiązań na.omit jest znacznie wolniejsze, ale to musi być zrównoważone z faktem, że zwraca i indeksy wierszy pominiętych wierszy jako atrybut na.action, podczas gdy inne powyższe rozwiązania nie.

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"

Dodano Zaktualizowano do odzwierciedlają najnowszą wersję dplyr i komentarze.

Dodane zostały zaktualizowane, aby odzwierciedlić najnowszą wersję tidyr i komentarze.

 121
Author: G. Grothendieck,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-16 14:51:35

To działa dla mnie:

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

Lub trochę bardziej ogólne:

library(dplyr) # 0.4
df %>% filter(complete.cases(.))

Miałoby to tę zaletę, że dane mogły zostać zmodyfikowane w łańcuchu przed przekazaniem ich do filtra.

Kolejny benchmark z większą liczbą kolumn:

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
 25
Author: Miha Trošt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-04 14:50:58

Oto wyniki porównawcze odpowiedzi Grothendiecka. na,omit () zajmuje 20x tyle czasu co pozostałe dwa rozwiązania. Myślę, że byłoby miło, gdyby dplyr miał funkcję do tego może jako część filtra.

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
 13
Author: user2503795,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-01 18:18:47

Jest to krótka funkcja, która pozwala określić kolumny (w zasadzie wszystko, co dplyr::select może zrozumieć), które nie powinny mieć żadnych wartości NA (wzorowane 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 jest teraz częścią tidyr : powyższe można zastąpić przez library("tidyr")]

Przykłady:

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
 9
Author: Jan Katins,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-09 16:10:37

Spróbuj tego

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

Lub nawet to

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

Powyższe polecenia dbają o sprawdzenie kompletności wszystkich kolumn (zmienna) w Twoich danych.rama.

 6
Author: infominer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-12 13:59:22

Tylko ze względu na kompletność, dplyr::filter można całkowicie uniknąć, ale nadal być w stanie komponować łańcuchy tylko za pomocą magrittr:extract (alias [):

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

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

Dodatkową zaletą jest szybkość, jest to najszybsza metoda spośród wariantów filter i na.omit (testowana przy użyciu mikrobenchmarks @ Miha Trošt).

 3
Author: mbask,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-23 08:09:56