Видаліть повторювані рядки за допомогою 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

Я спеціально шукаю рішення за допомогою dplyrпакету.

Відповіді:


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)

4
@dotcomken До цього часу можна було просто скористатисяdf %>% group_by(x, y) %>% do(head(.,1))
Холгер Брандл,

16
@MahbubulMajumder працює, але працює досить повільно. dplyr 0,3 матимеdistinct()
hadley

3
@hadley Мені подобається унікальна () і чітка () функція, проте всі вони видаляють 2-й дублікат з кадру даних. що робити, якщо я хочу, щоб усі перші зустрічі дублюючого значення були видалені? Як це можна було зробити? Дякуємо за будь-яку допомогу!
FlyingDutch

2
@MvZB - ти б не просто домовитись (desc ()), а потім використовувати окремо?
Вудсток

Я впевнений, що є просте рішення, але що робити, якщо я хочу позбутися обох повторюваних рядків? Я часто працюю з метаданими, пов’язаними з біологічними зразками, і якщо у мене є дублюючі ідентифікатори вибірки, я часто не можу бути впевнений, у якому рядку є правильні дані. Найбезпечніша ставка - скинути обидва, щоб уникнути помилкових асоціацій метаданих. Будь-яке просте рішення, окрім складання списку дублікатів зразків ідентифікаторів та фільтрації рядків із цими ідентифікаторами?
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

3
Це рішення виявляється набагато швидшим (в моєму випадку в 10 разів), ніж рішення, яке надає Хедлі.
Калімо

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)

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()
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.