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))
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.
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
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
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
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.
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).
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