web-dev-qa-db-fra.com

Rechercher des index de lignes dupliquées

La fonction dupliquée dans R effectue une recherche de ligne en double. Si nous voulons supprimer les doublons, il suffit d'écrire df[!duplicated(df),] et les doublons seront supprimés du bloc de données.

Mais comment trouver les index des données dupliquées? Si duplicated renvoie TRUE sur une ligne, cela signifie qu'il s'agit de la deuxième occurrence d'une telle ligne dans le cadre de données et que son index peut être facilement obtenu. Comment obtenir l'indice de première occurrence de cette ligne? Ou, en d'autres termes, un index avec lequel la ligne dupliquée est identique?

Je pourrais faire une boucle sur data.frame, mais je pense qu'il existe une réponse plus élégante à cette question.

64
annndrey

Ceci retourne un vecteur d'index logique:

duplicated(df) | duplicated(df[nrow(df):1, ])[nrow(df):1]

Voici un exemple:

df <- data.frame(a = c(1,2,3,4,1,5,6,4,2,1))

duplicated(df) | duplicated(df[nrow(df):1, ])[nrow(df):1]
#[1]  TRUE  TRUE FALSE  TRUE  TRUE FALSE FALSE  TRUE  TRUE  TRUE

which(duplicated(df) | duplicated(df[nrow(df):1, ])[nrow(df):1])
#[1]  1  2  4  5  8  9 10

Mise à jour (basé sur un commentaire):
La complexité de la commande peut être réduite si fromLast = TRUE est utilisé comme argument de fonction. C'est plus facile que de créer deux vecteurs inversés.

duplicated(df) | duplicated(df, fromLast = TRUE)

duplicated(df) | duplicated(df, fromLast = TRUE)
#[1]  TRUE  TRUE FALSE  TRUE  TRUE FALSE FALSE  TRUE  TRUE  TRUE

Comment ça marche?

La fonction duplicated est appliquée à la fois au bloc de données d'origine et au bloc de données avec un ordre de rang inversé. La sortie de ce dernier est à nouveau inversée. Notez que les premières occurrences de valeurs dupliquées dans les données d'origine sont les dernières occurrences de la version inversée. Ensuite, les deux vecteurs sont combinés en utilisant | depuis un TRUE dans au moins l’un d’eux indique une valeur dupliquée.

90
Sven Hohenstein

Si vous utilisez un fichier à clé data.table, vous pouvez utiliser la syntaxe élégante suivante

library(data.table)
DT <- data.table(A = rep(1:3, each=4), 
                 B = rep(1:4, each=3), 
                 C = rep(1:2, 6), key = "A,B,C")

DT[unique(DT[duplicated(DT)]),which=T]

Déballer

  • DT[duplicated(DT)] subdivise les lignes en double.

  • unique(...) ne renvoie que les combinaisons uniques des lignes dupliquées. Ceci concerne tous les cas avec plus d'un duplicata (doublons dupliqués, par exemple triplicata, etc.)

  • DT[..., which = T] Fusionne les lignes en double avec l'original, avec which=T Renvoyant le numéro de ligne (sans which = T, Les données seraient simplement renvoyées).

Vous pouvez aussi utiliser

 DT[,count := .N,by = list(A,B,C)][count>1, which=T]
18
mnel