Rimuovi le righe duplicate usando dplyr


128

Ho un data.frame come questo -

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

Vorrei rimuovere le righe duplicate in base alle prime due colonne. Uscita prevista -

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

Sto specificatamente cercando una soluzione usando il dplyrpacchetto.

Risposte:


137

Nota : dplyrora contiene la distinctfunzione per questo scopo.

Risposta originale di seguito:


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
)

Un approccio sarebbe quello di raggruppare, e quindi mantenere solo la prima riga:

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

(In dplyr 0.2 non avrai bisogno della zvariabile dummy e sarai solo in grado di scrivere row_number() == 1)

Ho anche pensato di aggiungere una slice()funzione che avrebbe funzionato come:

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

O forse una variazione di unique()questo ti permetterebbe di selezionare quali variabili usare:

df %>% unique(x, y)

4
@dotcomken Fino ad allora poteva anche solo usaredf %>% group_by(x, y) %>% do(head(.,1))
Holger Brandl il

16
@MahbubulMajumder che funzionerà, ma è piuttosto lento. dplyr 0.3 avràdistinct()
Hadley il

3
@hadley Mi piace la funzione unique () e distinct (), tuttavia rimuovono tutti il ​​secondo duplicato dal frame di dati. cosa succede se desidero rimuovere tutti i primi incontri del valore duplicato? Come si può fare? Grazie per qualsiasi aiuto!
FlyingDutch,

2
@MvZB - non ti limiteresti a organizzare (desc ()) e poi useresti distinto?
Woodstock,

Sono sicuro che esiste una soluzione semplice, ma cosa succede se desidero eliminare entrambe le righe duplicate? Lavoro spesso con metadati associati a campioni biologici e se ho ID campione duplicati, spesso non posso essere sicuro di quale riga abbia i dati corretti. La scommessa più sicura è scaricare entrambi per evitare associazioni errate di metadati. Qualche soluzione semplice oltre a creare un elenco di ID campione duplicati e filtrare le righe con tali ID?
glongo_fishes

191

Ecco una soluzione che utilizza 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
Questa soluzione sembra essere molto più veloce (10 volte nel mio caso) rispetto a quella fornita da Hadley.
Calimo,

101
Tecnicamente anche questa è una soluzione fornita da Hadley :-)
Tyler Rinker

27

Per completezza, funziona anche quanto segue:

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

Tuttavia, preferisco usare la soluzione distincte sospetto che sia anche più veloce.


7

Il più delle volte, la migliore soluzione sta usando distinct() da dplyr, come è già stato suggerito.

Tuttavia, ecco un altro approccio che utilizza la slice()funzione di 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)

Differenza dall'uso di distinct() funzione

Il vantaggio di questa soluzione è che rende esplicite quali righe vengono conservate dal frame di dati originale e può essere abbinato perfettamente alla arrange()funzione.

Supponiamo che tu abbia i dati sulle vendite dei clienti e che desideri conservare un record per cliente e desideri che tale record sia quello del loro ultimo acquisto. Quindi potresti scrivere:

customer_purchase_data %>%
   arrange(desc(Purchase_Date)) %>%
   group_by(Customer_ID) %>%
   slice(1)

3

Quando si selezionano le colonne in R per un set di dati ridotto, spesso si può finire con duplicati.

Queste due linee danno lo stesso risultato. Ciascuno genera un set di dati univoco con solo due colonne selezionate:

distinct(mtcars, cyl, hp);

summarise(group_by(mtcars, cyl, hp));

1

Se vuoi trovare le righe duplicate puoi usare find_duplicatesda hablar:

library(dplyr)
library(hablar)

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

df %>% find_duplicates()
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.