Herausfiltern doppelter / nicht eindeutiger Zeilen in data.table

77

Bearbeiten 2019: Diese Frage wurde vor Änderungen im data.tableNovember 2016 gestellt. Die akzeptierte Antwort unten finden Sie sowohl für die aktuelle als auch für die vorherige Methode.

Ich habe eine data.tableTabelle mit ungefähr 2,5 Millionen Zeilen. Es gibt zwei Spalten. Ich möchte alle Zeilen entfernen, die in beiden Spalten dupliziert sind. Früher hätte ich das für einen data.frame getan: df -> unique(df[,c('V1', 'V2')])aber das funktioniert nicht mit data.table. Ich habe es versucht, unique(df[,c(V1,V2), with=FALSE])aber es scheint immer noch nur mit dem Schlüssel der data.table und nicht mit der gesamten Zeile zu funktionieren.

Irgendwelche Vorschläge?

Prost, Davy

Beispiel

>dt
      V1   V2
[1,]  A    B
[2,]  A    C
[3,]  A    D
[4,]  A    B
[5,]  B    A
[6,]  C    D
[7,]  C    D
[8,]  E    F
[9,]  G    G
[10,] A    B

In der obigen Datentabelle, in der V2sich der Tabellenschlüssel befindet, werden nur die Zeilen 4, 7 und 10 entfernt.

> dput(dt)
structure(list(V1 = c("B", "A", "A", "A", "A", "A", "C", "C", 
"E", "G"), V2 = c("A", "B", "B", "B", "C", "D", "D", "D", "F", 
"G")), .Names = c("V1", "V2"), row.names = c(NA, -10L), class = c("data.table", 
"data.frame"), .internal.selfref = <pointer: 0x7fb4c4804578>, sorted = "V2")
Davy Kavanagh
quelle
3
Ohne Verwendung von Uniquedt[, .N,by=.(V1,V2)][,1:2]
Akki

Antworten:

95

Für v1.9.8 + ( veröffentlicht im November 2016 )

Von ?unique.data.table Standardmäßig werden alle Spalten verwendet (was mit übereinstimmt ?unique.data.frame)

unique(dt)
   V1 V2
1:  A  B
2:  A  C
3:  A  D
4:  B  A
5:  C  D
6:  E  F
7:  G  G

Oder verwenden Sie das byArgument, um eindeutige Kombinationen bestimmter Spalten zu erhalten (wie zuvor für).

unique(dt, by = "V2")
   V1 V2
1:  A  B
2:  A  C
3:  A  D
4:  B  A
5:  E  F
6:  G  G

Prior v1.9.8

Aus ?unique.data.tableist ersichtlich, dass das Aufrufen uniqueeiner Datentabelle nur für den Schlüssel funktioniert. Dies bedeutet, dass Sie den Schlüssel vor dem Aufruf auf alle Spalten zurücksetzen müssen unique.

library(data.table)
dt <- data.table(
  V1=LETTERS[c(1,1,1,1,2,3,3,5,7,1)],
  V2=LETTERS[c(2,3,4,2,1,4,4,6,7,2)]
)

Aufruf uniquemit einer Spalte als Schlüssel:

setkey(dt, "V2")
unique(dt)
     V1 V2
[1,]  B  A
[2,]  A  B
[3,]  A  C
[4,]  A  D
[5,]  E  F
[6,]  G  G

Andrie
quelle
1
Dies funktioniert nur, wenn kein Schlüssel gesetzt wurde. Ich werde die Frage oben bearbeiten, um das klar zu machen. Entschuldigung
Davy Kavanagh
2
wie akrun hier antwortete: stackoverflow.com/questions/40949023/… die erste version benötigt jetzt eine by = option zum arbeiten
Peter Pan
@ PeterPan der Link, den Sie gepostet haben, ist tot
wolfsatthedoor
16
@Andrie diese Lösung funktioniert nicht mehr, wie @PeterPan betonte. data.tablewird nicht mehr unique()in Schlüsseln berücksichtigt . Die Option unique(, by = c(keys))muss jetzt verwendet werden.
Altabq
4
Lassen Sie es wissen, dass altabq richtig ist und die Dinge in Schlüsseln mit Anführungszeichen umgeben sein müssen. Sie möchten also eindeutig (dt, by = c ("V1", "V2")) als Antwort.
Corey Levinson
9

Mit Ihrem Beispiel data.table ...

> dt<-data.table(V1 = c("B", "A", "A", "A", "A", "A", "C", "C", "E", "G"), V2 = c("A", "B", "B", "B", "C", "D", "D", "D", "F", "G"))
> setkey(dt,V2)

Betrachten Sie die folgenden Tests:

> haskey(dt) # obviously dt has a key, since we just set it
[1] TRUE

> haskey(dt[,list(V1,V2)]) # ... but this is treated like a "new" table, and does not have a key
[1] FALSE

> haskey(dt[,.SD]) # note that this still has a key
[1] TRUE

Sie können also die Spalten der Tabelle auflisten und diese dann übernehmen unique(), ohne den Schlüssel auf alle Spalten setzen oder löschen zu müssen (indem Sie ihn auf setzenNULL auflisten löschen zu müssen ( ), wie es die Lösung von @Andrie erfordert (und von @MatthewDowle bearbeitet) ). Die von @Pop und @Rahul vorgeschlagenen Lösungen haben bei mir nicht funktioniert.

Siehe Versuch 3 unten, der Ihrem ersten Versuch sehr ähnlich ist. Ihr Beispiel war nicht klar, deshalb bin ich mir nicht sicher, warum es nicht funktioniert hat. Es war auch vor ein paar Monaten, als Sie die Frage gepostet haben, also wurde sie vielleicht data.tableaktualisiert?

> unique(dt) # Try 1: wrong answer (missing V1=C and V2=D)
   V1 V2
1:  B  A
2:  A  B
3:  A  C
4:  A  D
5:  E  F
6:  G  G

> dt[!duplicated(dt)] # Try 2: wrong answer (missing V1=C and V2=D)
   V1 V2
1:  B  A
2:  A  B
3:  A  C
4:  A  D
5:  E  F
6:  G  G

> unique(dt[,list(V1,V2)]) # Try 3: correct answer; does not require modifying key
   V1 V2
1:  B  A
2:  A  B
3:  A  C
4:  A  D
5:  C  D
6:  E  F
7:  G  G

> setkey(dt,NULL)
> unique(dt) # Try 4: correct answer; requires key to be removed
   V1 V2
1:  B  A
2:  A  B
3:  A  C
4:  A  D
5:  C  D
6:  E  F
7:  G  G
dnlbrky
quelle
3
Vielleicht würde ein neues unique(...,use.key=FALSE)Argument helfen; jetzt als FR # 2483 abgelegt .
Matt Dowle
Hallo @MatthewDowle. Ja, das wäre eine schöne Annehmlichkeit. Ich denke, Ihr Kommentar in der FR ist auch richtig - wenn der Schlüssel eindeutig ist, use.key=FALSEkönnte er ignoriert werden.
dnlbrky
1
data.table 1.9.6 (und zweifellos frühere Versionen) verfügt über eine Option, mit by=der der Schlüssel überschrieben werden kann. Die Einstellung by=NULL"verwendet alle Spalten und verhält sich wie die analogen data.frame-Methoden."
JWilliman
1

unique(df) arbeitet an Ihrem Beispiel.

Pop
quelle
1

Dies sollte für Sie funktionieren

dt <- unique(dt, by = c('V1', 'V2'))
Magma
quelle
1
Das OP möchte doppelte Zeilen über die gesamte Zeile der Datentabelle entfernen und nicht nur über den Schlüssel. Das sollte das tun.
Magma
0

Unter Beibehaltung der data.table-Notation können Sie Folgendes verwenden:

unique(df[, .(V1, V2, V3), nomatch=0 ])

Wie hier https://stackoverflow.com/a/31875208/10087503

Ich habe die Geschwindigkeit dieser Version nicht mit der von Magma verglichen.

aclong
quelle