Eliminar filas duplicadas con dplyr

128

Tengo un data.frame como este:

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

Me gustaría eliminar filas duplicadas basadas en las dos primeras columnas. Rendimiento esperado -

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

Estoy buscando específicamente una solución usando el dplyrpaquete.

Nishanth
fuente

Respuestas:

137

Nota : dplyrahora contiene la distinctfunción para este propósito.

Respuesta original a continuación:


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 enfoque sería agrupar, y luego solo mantener la primera fila:

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

(En dplyr 0.2 no necesitará la zvariable ficticia y solo podrá escribir row_number() == 1)

También he estado pensando en agregar una slice()función que funcione como:

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

O tal vez una variación de unique()eso le permitiría seleccionar qué variables usar:

df %>% unique(x, y)
Hadley
fuente
44
@dotcomken Hasta entonces también podría usardf %>% group_by(x, y) %>% do(head(.,1))
Holger Brandl
16
@MahbubulMajumder que funcionará, pero es bastante lento. dplyr 0.3 tendrádistinct()
hadley
3
@hadley Me gusta la función unique () y distinct (), sin embargo, todas eliminan el segundo duplicado del marco de datos. ¿Qué sucede si deseo que se eliminen todos los primeros encuentros del valor duplicado? ¿Como se puede hacer esto? ¡Gracias por cualquier ayuda!
FlyingDutch
2
@MvZB: ¿no organizarías (desc ()) y luego usarías distinto?
Woodstock
Estoy seguro de que hay una solución simple, pero ¿qué pasa si quiero deshacerme de ambas filas duplicadas? A menudo trabajo con metadatos asociados con muestras biológicas y si tengo ID de muestra duplicados, a menudo no puedo estar seguro de qué fila tiene los datos correctos. La apuesta más segura es volcar ambos para evitar asociaciones de metadatos erróneas. ¿Alguna solución fácil además de hacer una lista de ID de muestra duplicados y filtrar filas con esas ID?
glongo_fishes
191

Aquí hay una solución usando 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
fuente
3
Esta solución parece ser mucho más rápida (10 veces en mi caso) que la proporcionada por Hadley.
Calimo
101
Técnicamente, esta también es una solución proporcionada por Hadley :-)
Tyler Rinker
27

Para completar, también funciona lo siguiente:

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

Sin embargo, prefiero usar la solución distincty sospecho que también es más rápida.

Konrad Rudolph
fuente
7

La mayoría de las veces, la mejor solución es usar distinct()dplyr, como ya se ha sugerido.

Sin embargo, aquí hay otro enfoque que utiliza la slice()función 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)

Diferencia de usar la distinct()función

La ventaja de esta solución es que hace explícito qué filas se retienen del marco de datos original, y puede emparejarse muy bien con la arrange()función.

Supongamos que tenía datos de ventas de clientes y quería conservar un registro por cliente, y desea que ese registro sea el de su última compra. Entonces podrías escribir:

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

Al seleccionar columnas en R para un conjunto de datos reducido, a menudo puede terminar con duplicados.

Estas dos líneas dan el mismo resultado. Cada uno genera un conjunto de datos único con solo dos columnas seleccionadas:

distinct(mtcars, cyl, hp);

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

Si desea encontrar las filas que están duplicadas, puede usarlas find_duplicatesdesde hablar:

library(dplyr)
library(hablar)

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

df %>% find_duplicates()
davsjob
fuente