Entfernen Sie doppelte Zeilen mit dplyr

128

Ich habe einen data.frame wie diesen -

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

Ich möchte doppelte Zeilen basierend auf den ersten beiden Spalten entfernen. Erwartete Ausgabe -

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

Ich suche speziell nach einer Lösung mit dplyrPaket.

Nishanth
quelle

Antworten:

137

Hinweis : dplyrEnthält jetzt die distinctFunktion für diesen Zweck.

Ursprüngliche Antwort unten:


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
)

Ein Ansatz wäre, zu gruppieren und dann nur die erste Zeile beizubehalten:

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

(In dplyr 0.2 benötigen Sie die Dummy- zVariable nicht und können nur schreiben. row_number() == 1)

Ich habe auch darüber nachgedacht, eine slice()Funktion hinzuzufügen , die wie folgt funktionieren würde:

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

Oder mit einer Variation davon können unique()Sie auswählen, welche Variablen verwendet werden sollen:

df %>% unique(x, y)
Hadley
quelle
4
@dotcomken Bis dahin konnte auch nur verwendet werdendf %>% group_by(x, y) %>% do(head(.,1))
Holger Brandl
16
@ MahbubulMajumder das wird funktionieren, ist aber ziemlich langsam. dplyr 0.3 wirddistinct()
hadley
3
@ Hadley Ich mag die Funktion unique () und unique (), aber alle entfernen das 2. Duplikat aus dem Datenrahmen. Was ist, wenn alle ersten Begegnungen mit dem doppelten Wert entfernt werden sollen? Wie könnte das gemacht werden? Vielen Dank für jede Hilfe!
FlyingDutch
2
@MvZB - würdest du nicht einfach (desc ()) arrangieren und dann eindeutig verwenden?
Woodstock
Ich bin mir sicher, dass es eine einfache Lösung gibt, aber was ist, wenn ich beide doppelten Zeilen entfernen möchte? Ich arbeite oft mit Metadaten, die mit biologischen Proben verknüpft sind, und wenn ich doppelte Proben-IDs habe, kann ich oft nicht sicher sein, welche Zeile die richtigen Daten enthält. Am sichersten ist es, beide zu sichern, um fehlerhafte Metadatenzuordnungen zu vermeiden. Gibt es eine einfache Lösung, außer eine Liste doppelter Beispiel-IDs zu erstellen und Zeilen mit diesen IDs herauszufiltern?
glongo_fishes
191

Hier ist eine Lösung mit 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
Davechilder
quelle
3
Diese Lösung scheint viel schneller zu sein (in meinem Fall zehnmal) als die von Hadley.
Calimo
101
Auch technisch ist dies eine Lösung von Hadley :-)
Tyler Rinker
27

Der Vollständigkeit halber funktioniert auch Folgendes:

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

Ich bevorzuge jedoch die Verwendung der Lösung distinctund vermute, dass sie auch schneller ist.

Konrad Rudolph
quelle
7

Die beste Lösung ist distinct()meistens die Verwendung von dplyr, wie bereits vorgeschlagen wurde.

Hier ist jedoch ein anderer Ansatz, der die slice()Funktion von dplyr verwendet.

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

Unterschied zur Verwendung der distinct()Funktion

Der Vorteil dieser Lösung besteht darin, dass explizit angegeben wird, welche Zeilen vom ursprünglichen Datenrahmen beibehalten werden, und dass sie sich gut mit der arrange()Funktion koppeln lässt .

Angenommen, Sie hatten Kundenverkaufsdaten und wollten einen Datensatz pro Kunde behalten, und Sie möchten, dass dieser Datensatz der Datensatz aus dem letzten Kauf ist. Dann könnten Sie schreiben:

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

Wenn Sie Spalten in R für einen reduzierten Datensatz auswählen, kann es häufig zu Duplikaten kommen.

Diese beiden Zeilen ergeben das gleiche Ergebnis. Jeder gibt einen eindeutigen Datensatz mit nur zwei ausgewählten Spalten aus:

distinct(mtcars, cyl, hp);

summarise(group_by(mtcars, cyl, hp));
Anton Andreev
quelle
1

Wenn Sie möchten , um die Zeilen zu finden , die dupliziert werden Sie verwenden können , find_duplicatesaus hablar:

library(dplyr)
library(hablar)

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

df %>% find_duplicates()
Davsjob
quelle