使用dplyr删除重复的行

Nis*_*nth 113 r dplyr

我有一个像这样的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
Run Code Online (Sandbox Code Playgroud)

我想根据前两列删除重复的行.预期产量 -

df[!duplicated(df[,1:2]),]
  x y z
1 0 1 1
2 1 0 2
4 1 1 4
Run Code Online (Sandbox Code Playgroud)

我正在寻找使用dplyr包的解决方案.

dav*_*ers 181

这是一个使用的解决方案dplyr 0.3.

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)
    x y z
  1 0 1 1
  2 1 0 2
  3 1 1 4
Run Code Online (Sandbox Code Playgroud)

更新了dplyr 0.5

dplyr版本0.5的默认行为distinct()只返回...参数中指定的列.

要获得原始结果,您现在必须使用:

df %>% distinct(x, y, .keep_all = TRUE)
Run Code Online (Sandbox Code Playgroud)

  • 从技术上讲,这也是哈德利提供的解决方案:-) (91认同)
  • 这个解决方案似乎比Hadley提供的解决方案快得多(在我的情况下是10倍). (3认同)

had*_*ley 121

注意: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
)
Run Code Online (Sandbox Code Playgroud)

一种方法是分组,然后只保留第一行:

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
Run Code Online (Sandbox Code Playgroud)

(在dplyr 0.2中你不需要虚拟z变量,只能写row_number() == 1)

我一直在考虑添加一个slice()功能如下的函数:

df %>% group_by(x, y) %>% slice(from = 1, to = 1)
Run Code Online (Sandbox Code Playgroud)

或者可以unique()使用它的变体来选择要使用的变量:

df %>% unique(x, y)
Run Code Online (Sandbox Code Playgroud)

  • @MahbubulMajumder会起作用,但速度很慢.dplyr 0.3将具有`distinct()` (14认同)
  • @dotcomken在此之前也可以使用`df%>%group_by(x,y)%>%do(head(.,1))` (4认同)
  • @hadley我喜欢unique()和distinct()函数,但是,它们都从数据框中删除了第二个副本.如果我想删除重复值的所有第一次遇到怎么办?怎么可以这样做?谢谢你的帮助! (3认同)
  • @MvZB - 你不会只是安排(desc())然后使用不同的吗? (2认同)
  • 我确信有一个简单的解决方案,但是如果我想删除两个重复的行怎么办?我经常使用与生物样本相关的元数据,如果我有重复的样本 ID,我通常无法确定哪一行具有正确的数据。最安全的选择是转储两者以避免错误的元数据关联。除了制作重复样本 ID 的列表并过滤掉具有这些 ID 的行之外,还有什么简单的解决方案吗? (2认同)

Kon*_*lph 25

为了完整起见,以下也适用:

df %>% group_by(x) %>% filter (! duplicated(y))
Run Code Online (Sandbox Code Playgroud)

但是,我更喜欢使用解决方案distinct,我怀疑它也更快.


bsc*_*idr 8

大多数情况下,最好的解决方案是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)
Run Code Online (Sandbox Code Playgroud)

与使用distinct()函数的区别

这个解决方案的优点是它明确地从原始数据帧中保留了哪些行,并且它可以很好地与arrange()函数配对。

假设您有客户销售数据,并且希望为每位客户保留一条记录,并且希望该记录是他们最近一次购买的记录。然后你可以写:

customer_purchase_data %>%
   arrange(desc(Purchase_Date)) %>%
   group_by(Customer_ID) %>%
   slice(1)
Run Code Online (Sandbox Code Playgroud)