dplyr을 사용하여 중복 행 제거


128

나는 이와 같은 data.frame을 가지고있다-

set.seed(123)
df = data.frame(x=sample(0:1,10,replace=T),y=sample(0:1,10,replace=T),z=1:10)
> df
   x y  z
1  0 1  1
2  1 0  2
3  0 1  3
4  1 1  4
5  1 0  5
6  0 1  6
7  1 0  7
8  1 0  8
9  1 0  9
10 0 1 10

처음 두 열을 기준으로 중복 행을 제거하고 싶습니다. 예상 출력-

df[!duplicated(df[,1:2]),]
  x y z
1 0 1 1
2 1 0 2
4 1 1 4

구체적으로 dplyr패키지를 사용하는 솔루션을 찾고 있습니다.

답변:


137

참고 : dplyr이제이 distinct목적을위한 기능이 포함되어 있습니다 .

아래의 원래 답변 :


library(dplyr)
set.seed(123)
df <- data.frame(
  x = sample(0:1, 10, replace = T),
  y = sample(0:1, 10, replace = T),
  z = 1:10
)

한 가지 방법은 그룹화 한 다음 첫 번째 행만 유지하는 것입니다.

df %>% group_by(x, y) %>% filter(row_number(z) == 1)

## Source: local data frame [3 x 3]
## Groups: x, y
## 
##   x y z
## 1 0 1 1
## 2 1 0 2
## 3 1 1 4

(dplyr 0.2에서는 더미 z변수 가 필요하지 않으며 쓸 수 있습니다 row_number() == 1)

또한 slice()다음과 같은 기능을 추가하는 것에 대해 생각했습니다 .

df %>% group_by(x, y) %>% slice(from = 1, to = 1)

또는 그 변형 unique()으로 사용할 변수를 선택할 수 있습니다.

df %>% unique(x, y)

4
@dotcomken 그때까지도 사용할 수 있습니다df %>% group_by(x, y) %>% do(head(.,1))
Holger Brandl

16
@MahbubulMajumder 작동하지만 꽤 느립니다. dplyr 0.3은 다음을 가질 것입니다distinct()
hadley

3
@hadley unique () 및 distinct () 함수가 마음에 들지만 데이터 프레임에서 두 번째 복제본을 모두 제거합니다. 중복 값의 첫 번째 발생을 모두 제거하려면 어떻게해야합니까? 어떻게 이럴 수 있습니까? 도움을 주셔서 감사합니다!
FlyingDutch

2
@ MvZB-그냥 배열 (desc ()) 한 다음 distinct를 사용하지 않습니까?
Woodstock

간단한 해결책이 있다고 확신하지만 두 행을 모두 제거하려면 어떻게해야합니까? 생물학적 샘플과 관련된 메타 데이터를 사용하는 경우가 많으며 샘플 ID가 중복되면 어떤 행에 올바른 데이터가 있는지 확신 할 수없는 경우가 많습니다. 가장 안전한 방법은 잘못된 메타 데이터 연결을 피하기 위해 둘 다 덤프하는 것입니다. 중복 샘플 ID 목록을 만들고 해당 ID로 행을 필터링하는 것 외에 쉬운 솔루션이 있습니까?
glongo_fishes

191

다음을 사용하는 솔루션이 dplyr >= 0.5있습니다.

library(dplyr)
set.seed(123)
df <- data.frame(
  x = sample(0:1, 10, replace = T),
  y = sample(0:1, 10, replace = T),
  z = 1:10
)

> df %>% distinct(x, y, .keep_all = TRUE)
    x y z
  1 0 1 1
  2 1 0 2
  3 1 1 4

3
이 솔루션은 Hadley가 제공하는 솔루션보다 훨씬 빠릅니다 (필자의 경우 10 배).
Calimo

101
기술적으로 이것은 역시 Hadley가 제공 한 솔루션입니다.
Tyler Rinker

27

완전성을 위해 다음도 작동합니다.

df %>% group_by(x) %>% filter (! duplicated(y))

그러나 나는를 사용하는 솔루션을 선호하며 distinct더 빠르다고 생각합니다.


7

대부분의 경우 distinct()이미 제안 된 것처럼 최상의 솔루션은 dplyr에서 사용 하는 것입니다.

그러나 slice()dplyr 의 함수 를 사용하는 또 다른 방법이 있습니다.

# Generate fake data for the example
  library(dplyr)
  set.seed(123)
  df <- data.frame(
    x = sample(0:1, 10, replace = T),
    y = sample(0:1, 10, replace = T),
    z = 1:10
  )

# In each group of rows formed by combinations of x and y
# retain only the first row

    df %>%
      group_by(x, y) %>%
      slice(1)

distinct()기능 사용과의 차이점

이 솔루션의 장점은 원래 데이터 프레임에서 어떤 행이 유지되는지 명시 적으로 만들고 arrange()함수 와 잘 어울릴 수 있다는 것입니다.

고객 판매 데이터가 있고 고객 당 하나의 레코드를 유지하려고하며 해당 레코드가 최근 구매의 레코드가 되길 원한다고 가정 해 봅시다. 그럼 당신은 쓸 수 있습니다 :

customer_purchase_data %>%
   arrange(desc(Purchase_Date)) %>%
   group_by(Customer_ID) %>%
   slice(1)

3

축소 된 데이터 세트에 대해 R에서 열을 선택할 때 종종 중복으로 끝날 수 있습니다.

이 두 줄은 같은 결과를 제공합니다. 각각 두 개의 선택된 열만있는 고유 한 데이터 세트를 출력합니다.

distinct(mtcars, cyl, hp);

summarise(group_by(mtcars, cyl, hp));

1

당신이 사용할 수있는 중복되는 행 찾으려는 경우 find_duplicates에서를 hablar:

library(dplyr)
library(hablar)

df <- tibble(a = c(1, 2, 2, 4),
             b = c(5, 2, 2, 8))

df %>% find_duplicates()
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.