Usuń zduplikowane wiersze za pomocą dplyr


128

Mam taką ramkę danych -

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

Chciałbym usunąć zduplikowane wiersze na podstawie pierwszych dwóch kolumn. Oczekiwany wynik -

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

Szukam konkretnie rozwiązania wykorzystującego dplyrpakiet.

Odpowiedzi:


137

Uwaga : dplyrteraz zawiera distinctfunkcję do tego celu.

Oryginalna odpowiedź poniżej:


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
)

Jednym podejściem byłoby zgrupowanie, a następnie zachowanie tylko pierwszego wiersza:

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

(W dplyr 0.2 nie będziesz potrzebować zzmiennej zastępczej i będziesz mógł po prostu pisać row_number() == 1)

Myślałem też o dodaniu slice()funkcji, która działałaby jak:

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

A może odmiana unique()tego pozwoliłaby Ci wybrać, których zmiennych użyć:

df %>% unique(x, y)

4
@dotcomken Do tego czasu można też po prostu używaćdf %>% group_by(x, y) %>% do(head(.,1))
Holger Brandl

16
@MahbubulMajumder, które będzie działać, ale jest dość powolne. dplyr 0.3 będzie miałdistinct()
hadley

3
@hadley Podoba mi się funkcja unique () i unique (), jednak wszystkie one usuwają drugi duplikat z ramki danych. co jeśli chcę usunąć wszystkie pierwsze spotkania zduplikowanej wartości? Jak można to zrobić? Dzięki za pomoc!
FlyingDutch

2
@MvZB - czy nie mógłbyś po prostu zaaranżować (desc ()), a następnie użyć różnicy?
Woodstock

Jestem pewien, że istnieje proste rozwiązanie, ale co jeśli chcę pozbyć się obu zduplikowanych wierszy? Często pracuję z metadanymi związanymi z próbkami biologicznymi i jeśli mam zduplikowane identyfikatory próbek, często nie mam pewności, który wiersz zawiera prawidłowe dane. Najbezpieczniejszym zakładem jest zrzucenie obu, aby uniknąć błędnych skojarzeń metadanych. Czy jest jakieś łatwe rozwiązanie poza utworzeniem listy zduplikowanych identyfikatorów próbek i odfiltrowaniem wierszy z tymi identyfikatorami?
glongo_fishes

191

Oto rozwiązanie wykorzystujące 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
To rozwiązanie wydaje się znacznie szybsze (w moim przypadku 10 razy) niż to, które oferuje Hadley.
Calimo

101
Technicznie też jest to rozwiązanie dostarczone przez Hadley :-)
Tyler Rinker

27

Ze względu na kompletność działają również następujące zasady:

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

Jednak wolę rozwiązanie z użyciem distincti podejrzewam, że jest też szybsze.


7

W większości przypadków najlepszym rozwiązaniem jest użycie distinct()firmy dplyr, jak już zostało zasugerowane.

Jednak tutaj jest inne podejście, które wykorzystuje slice()funkcję z 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)

Różnica w porównaniu z używaniem distinct()funkcji

Zaletą tego rozwiązania jest to, że wyraźnie określa, które wiersze są zachowywane z oryginalnej ramki danych, i można je ładnie łączyć z arrange()funkcją.

Załóżmy, że masz dane dotyczące sprzedaży klientów i chcesz zachować jeden rekord dla każdego klienta i chcesz, aby był to rekord z ostatniego zakupu. Wtedy możesz napisać:

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

3

Wybierając kolumny w R dla zredukowanego zestawu danych, często możesz skończyć z duplikatami.

Te dwie linie dają ten sam wynik. Każdy generuje unikalny zestaw danych z tylko dwiema wybranymi kolumnami:

distinct(mtcars, cyl, hp);

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

1

Jeśli chcesz znaleźć zduplikowane wiersze, możesz użyć find_duplicatesz hablar:

library(dplyr)
library(hablar)

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

df %>% find_duplicates()
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.