dplyr을 사용하여 data.frame의 전체 케이스 필터링 (케이스 별 삭제)


97

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

4
complete.cases벡터 만 받아들이지 않습니다. 전체 데이터 프레임도 필요합니다.
joran

그러나 그것은 dplyr의 필터 기능의 일부로 작동하지 않습니다 . 나는 충분히 명확하지 않았고 내 질문을 업데이트했다고 생각합니다.
user2503795

1
dplyr에서 작동하지 않는 방법을 정확하게 보여줄 수 있다면 도움이 될 것이지만 필터로 시도하면 잘 작동합니다.
joran 2014 년

답변:


185

이 시도:

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"

ADDED 최신 버전의 dplyr 및 댓글을 반영하도록 업데이트했습니다.

ADDED 최신 버전의 깔끔하고 댓글을 반영하도록 업데이트했습니다.


답장으로 돌아와서 유용한 답변을 확인했습니다!
infominer

1
감사! 벤치 마크 결과를 추가했습니다. na.omit()성능이 매우 좋지 않지만 빠르다.
user2503795

1
이것은 지금도 작동합니다 : df %>% filter(complete.cases(.)). dplyr의 최근 변경 사항이이를 가능하게했는지 확실하지 않습니다.
user2503795

@ jan-katins가 지적했듯이 Tidyverse 함수는라고 불리 drop_na므로 이제 다음과 같이 할 수 있습니다 df %>% drop_na().
cbrnr

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

1
귀하의 답변을 "."로 업데이트했습니다. complete.cases 및 추가 된 벤치 마크에서-마음에 들지 않기를 바랍니다. :-)
talat

:) 그렇지 않습니다. 감사합니다.
Miha Trošt 2015 년

1
df %>% slice(which(complete.cases(.)))위의 벤치 마크에서 필터 방식보다 약 20 % 더 빠른 성능을 발견 했습니다.
talat

다른 dplyr 명령 (예 : group_by ())과 함께 dplyr 파이프에서이 필터를 사용하는 경우, %>% data.frame() %>%complete.cases (.)에서 작동하지 않기 때문에 시도하고 필터링하기 전에 추가 해야합니다. tibbles 또는 그룹화 된 tibbles 또는 무언가. 또는 적어도 그것은 내가 경험 한 것입니다.
C. Denney

16

다음은 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

12

이것은 dplyr::selectNA 값이 없어야 하는 열 (기본적으로 이해할 수있는 모든 것)을 지정할 수있는 짧은 함수입니다 (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

0.5와 같은 컷오프를 추가하고 열별로 처리하는 것이 더 유용하지 않을까요? 사례 : 누락 된 데이터가 50 % 이상인 변수를 제거합니다. 예 : data [, -which (colMeans (is.na (data))> 0.5)] tidyr로 할 수 있으면 좋을 것 같습니다.
Monduiz

@Monduiz 이것은 필요한 변수가 지금은 ... 없기 때문에 (변수가 다음 NA 많이있다) 더 많은 데이터를 추가 파이프 라인의 다음 단계를 실패 할 수 있음을 의미한다
월 Katins

맞습니다.
Monduiz

6

이 시도

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

또는 이것도

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

위의 명령은 data.frame의 모든 열 (변수)에 대한 완전성 검사를 처리합니다.


감사. 나는 충분히 명확하지 않은 것 같습니다 (질문이 업데이트되었습니다). complete.cases (df)에 대해 알고 있지만 dplyr필터 함수의 일부로 수행하고 싶습니다 . 즉 등 dplyr 체인에 깔끔한 통합 할 수 있습니다 것
user2503795

G.Grothendieck @으로 답을 확인
infominer

에서 dplyr:::do.data.frameenv$. <- .data환경에 점이 추가됩니다. magrittr에서 그런 진술하지 : "%> %"`
G. 그로 텐 디크

댓글을 잘못 입력 한 것 같습니다.
G. Grothendieck

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

추가 보너스는 속도입니다. 이는 filterna.omit변형 중에서 가장 빠른 방법입니다 (@Miha Trošt microbenchmarks를 사용하여 테스트 됨).


Miha Trošt의 데이터로 벤치 마크를 수행 할 때 사용 extract()filter(). 그러나를 사용하여 더 작은 데이터 프레임을 만들면 df <- df[1:100, 1:10]그림이 변경되고 extract()가장 빠릅니다.
Stibu

당신이 올바른지. Miha Trošt 벤치 마크 magrittr::extract에서만 가장 빠른 방법 인 것 같습니다 n <= 5e3.
mbask
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.