94 votes

Filtrage des lignes dupliquées/non uniques dans data.table

Editer 2019 : Cette question a été posée avant les changements dans data.table en novembre 2016, voir la réponse acceptée ci-dessous pour la méthode actuelle et la méthode précédente.

J'ai un data.table avec environ 2,5 millions de lignes. Il y a deux colonnes. Je veux supprimer toutes les lignes qui sont dupliquées dans les deux colonnes. Auparavant, pour un data.frame, j'aurais fait ceci : df -> unique(df[,c('V1', 'V2')]) mais cela ne fonctionne pas avec data.table. J'ai essayé unique(df[,c(V1,V2), with=FALSE]) mais il semble qu'elle n'opère toujours que sur la clé du tableau data.table et non sur la ligne entière.

Des suggestions ?

A la vôtre, Davy

Exemple

>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

dans le tableau de données ci-dessus où V2 est la clé de la table, seules les lignes 4, 7 et 10 seront supprimées.

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

115voto

Andrie Points 66979

Pour les versions 1.9.8 et suivantes ( publié en novembre 2016 )

De ?unique.data.table Par défaut, toutes les colonnes sont utilisées (ce qui est cohérent avec l'utilisation de l'option ?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

Ou en utilisant le by afin d'obtenir des combinaisons uniques de colonnes spécifiques (comme les clés utilisées précédemment).

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

Avant v1.9.8

De ?unique.data.table il est clair qu'en appelant unique sur une table de données ne fonctionne que sur la clé. Cela signifie que vous devez réinitialiser la clé de toutes les colonnes avant d'appeler 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)]
)

Appel à unique avec une colonne comme clé :

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

9voto

dnlbrky Points 891

Avec votre exemple 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)

Considérez les tests suivants :

> 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

Ainsi, vous pouvez énumérer les colonnes de la table et ensuite prendre le unique() de cela, sans qu'il soit nécessaire de définir la clé sur toutes les colonnes ou de la laisser tomber (en la définissant sur NULL ) comme l'exige la solution de @Andrie (et modifiée par @MatthewDowle). Les solutions proposées par @Pop et @Rahul n'ont pas fonctionné pour moi.

Voir l'essai 3 ci-dessous, qui est très similaire à votre essai initial. Votre exemple n'était pas clair et je ne sais pas pourquoi il n'a pas fonctionné. De plus, la question a été postée il y a quelques mois, donc peut-être que le problème n'est pas résolu. data.table a été mis à jour ?

> 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

1voto

Pop Points 1800

unique(df) fonctionne sur votre exemple.

1voto

Magma Points 95

Cela devrait fonctionner pour vous

dt <- unique(dt, by = c('V1', 'V2'))

0voto

aclong Points 111

Garder la notation data.table que vous pouvez utiliser :

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

Comme ici https://stackoverflow.com/a/31875208/10087503

Je n'ai pas comparé la vitesse de cette version à celle de Magma.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X