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.

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)

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

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.


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)

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

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()
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.