Supprimer les lignes dupliquées à l'aide de dplyr

128

J'ai un data.frame comme celui-ci -

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

Je voudrais supprimer les lignes en double en fonction des deux premières colonnes. Production attendue -

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

Je recherche spécifiquement une solution utilisant dplyrpackage.

Nishanth
la source

Réponses:

137

Remarque : dplyrcontient maintenant la distinctfonction à cet effet.

Réponse originale ci-dessous:


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
)

Une approche serait de regrouper, puis de ne conserver que la première ligne:

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

(Dans dplyr 0.2, vous n'aurez pas besoin de la zvariable factice et pourrez simplement écrire row_number() == 1)

J'ai également pensé à ajouter une slice()fonction qui fonctionnerait comme:

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

Ou peut-être qu'une variante de unique()cela vous permettrait de sélectionner les variables à utiliser:

df %>% unique(x, y)
hadley
la source
4
@dotcomken Jusque-là pourrait aussi simplement utiliserdf %>% group_by(x, y) %>% do(head(.,1))
Holger Brandl
16
@MahbubulMajumder qui fonctionnera, mais est assez lent. dplyr 0.3 auradistinct()
hadley
3
@hadley J'aime les fonctions unique () et distinct (), cependant, elles suppriment toutes le 2e doublon de la trame de données. Que faire si je veux que toutes les premières rencontres de la valeur en double soient supprimées? Comment cela pourrait-il être fait? Merci pour toute aide!
FlyingDutch
2
@MvZB - ne voudriez-vous pas simplement organiser (desc ()) et ensuite utiliser distinct?
Woodstock
Je suis sûr qu'il existe une solution simple, mais que faire si je veux me débarrasser des deux lignes en double? Je travaille souvent avec des métadonnées associées à des échantillons biologiques et si j'ai des identifiants d'échantillons en double, je ne peux souvent pas être sûr de quelle ligne contient les données correctes. Le pari le plus sûr est de vider les deux pour éviter les associations de métadonnées erronées. Une solution simple en plus de créer une liste d'ID d'échantillons en double et de filtrer les lignes avec ces ID?
glongo_fishes
191

Voici une solution utilisant 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
davechilders
la source
3
Cette solution semble être beaucoup plus rapide (10 fois dans mon cas) que celle fournie par Hadley.
Calimo
101
Techniquement, c'est aussi une solution fournie par Hadley :-)
Tyler Rinker
27

Par souci d'exhaustivité, ce qui suit fonctionne également:

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

Cependant, je préfère utiliser la solution distinctet je soupçonne que c'est plus rapide aussi.

Konrad Rudolph
la source
7

La plupart du temps, la meilleure solution est d'utiliser distinct()de dplyr, comme cela a déjà été suggéré.

Cependant, voici une autre approche qui utilise la slice()fonction de 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)

Différence par rapport à l'utilisation du distinct() fonction

L'avantage de cette solution est qu'elle rend explicite les lignes qui sont conservées à partir du dataframe d'origine, et elle peut bien s'associer avec la arrange()fonction.

Supposons que vous disposiez de données sur les ventes des clients et que vous vouliez conserver un enregistrement par client, et que vous souhaitiez que cet enregistrement soit celui de leur dernier achat. Ensuite, vous pourriez écrire:

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

Lorsque vous sélectionnez des colonnes dans R pour un ensemble de données réduit, vous pouvez souvent vous retrouver avec des doublons.

Ces deux lignes donnent le même résultat. Chacun génère un ensemble de données unique avec deux colonnes sélectionnées uniquement:

distinct(mtcars, cyl, hp);

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

Si vous souhaitez rechercher les lignes dupliquées, vous pouvez utiliser à find_duplicatespartir de hablar:

library(dplyr)
library(hablar)

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

df %>% find_duplicates()
davsjob
la source