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.

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)

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

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.


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)

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

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()
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.