Удалите повторяющиеся строки с помощью dplyr

128

У меня есть такой data.frame -

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

Я хочу удалить повторяющиеся строки на основе первых двух столбцов. Ожидаемый результат -

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

Я специально ищу решение, использующее dplyrpackage.

Nishanth
источник

Ответы:

137

Примечание : dplyrтеперь содержит distinctфункцию для этой цели.

Оригинальный ответ ниже:


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 %>% 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

(В dplyr 0.2 вам не понадобится фиктивная zпеременная, и вы просто сможете писать row_number() == 1)

Я также думал о добавлении slice()функции, которая работала бы так:

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

Или, может быть, вариант unique()этого позволит вам выбрать, какие переменные использовать:

df %>% unique(x, y)
Hadley
источник
4
@dotcomken До этого можно было просто использоватьdf %>% group_by(x, y) %>% do(head(.,1))
Хольгер Брандл
16
@MahbubulMajumder, который будет работать, но довольно медленно. dplyr 0.3 будет иметьdistinct()
хэдли
3
@hadley Мне нравятся функции unique () и independent (), однако все они удаляют второй дубликат из фрейма данных. что, если я хочу удалить все первые совпадения повторяющегося значения? Как это можно было сделать? Спасибо за любую помощь!
FlyingDutch
2
@MvZB - не могли бы вы просто упорядочить (desc ()), а затем использовать разные?
Woodstock
Я уверен, что есть простое решение, но что, если я хочу избавиться от обеих повторяющихся строк? Я часто работаю с метаданными, связанными с биологическими образцами, и если у меня есть повторяющиеся идентификаторы образцов, я часто не могу быть уверен, в какой строке указаны правильные данные. Самый безопасный вариант - сбросить оба, чтобы избежать ошибочных ассоциаций метаданных. Любое простое решение, кроме создания списка повторяющихся идентификаторов образцов и фильтрации строк с этими идентификаторами?
glongo_fishes
191

Вот решение с использованием 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
источник
3
Это решение оказывается намного быстрее (в моем случае в 10 раз), чем решение, предоставленное Хэдли.
Calimo
101
Технически это тоже решение, предоставленное Хэдли :-)
Тайлер Ринкер
27

Для полноты картины также работает следующее:

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

Однако я предпочитаю использовать решение distinct, и подозреваю, что оно быстрее.

Конрад Рудольф
источник
7

В большинстве случаев лучшим решением является использование distinct()dplyr, как уже предлагалось.

Однако вот еще один подход, в котором используется slice()функция из 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)

Отличие от использования distinct()функции

Преимущество этого решения состоит в том, что в нем явно указано, какие строки сохраняются из исходного фрейма данных, и оно может хорошо сочетаться с arrange()функцией.

Предположим, у вас есть данные о продажах клиентов, и вы хотите сохранить по одной записи для каждого покупателя, и вы хотите, чтобы эта запись была записью об их последней покупке. Тогда вы могли написать:

customer_purchase_data %>%
   arrange(desc(Purchase_Date)) %>%
   group_by(Customer_ID) %>%
   slice(1)
bschneidr
источник
3

При выборе столбцов в R для сокращенного набора данных вы часто можете получить дубликаты.

Эти две строки дают одинаковый результат. Каждый выводит уникальный набор данных только с двумя выбранными столбцами:

distinct(mtcars, cyl, hp);

summarise(group_by(mtcars, cyl, hp));
Антон Андреев
источник
1

Если вы хотите , чтобы найти строки, которые дублируются вы можете использовать find_duplicatesс hablar:

library(dplyr)
library(hablar)

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

df %>% find_duplicates()
davsjob
источник