使用dplyr去除重复的行

196
我有一个类似这样的数据框 -
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包的解决方案。

6个回答

269
这里提供使用 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
这个解决方案似乎比 Hadley 提供的那个要快得多(在我的情况下快了10倍)。 - Calimo
140
技术上来说,这也是 Hadley 提供的一种解决方案 :-) - Tyler Rinker
你可以通过排列来解决关于哪些行需要删除的问题,它会保留第一行。 - Alvaro Morales

164
< p > < em > 注意 :现在 < code > dplyr 包含了用于此目的的 < code > distinct 函数。 < p>以下是原始答案:
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
在那之前,你也可以使用以下代码:df %>% group_by(x, y) %>% do(head(.,1))。该代码将对 DataFrame 按 xy 进行分组,并返回每个组的第一行。 - Holger Brandl
19
@MahbubulMajumder那个做法可行,但速度较慢。dplyr 0.3将拥有distinct()函数。 - hadley
3
@hadley 我很喜欢unique()和distinct()函数,但它们都会从数据框中删除第二个重复项。如果我想删除所有重复值的第一个出现,应该怎么做?感谢任何帮助! - FlyingDutch
2
@MvZB - 你是不是只需要使用 arrange(desc()) 然后再使用 distinct? - Woodstock
2
我相信有一个简单的解决方案,但如果我想要同时去除重复的行怎么办?我经常处理与生物样本相关的元数据,如果我有重复的样本ID,我通常无法确定哪一行具有正确的数据。最安全的方法是将两者都删除以避免错误的元数据关联。除了制作重复样本ID列表并过滤掉这些ID的行之外,还有什么简单的解决方案吗? - glongo_fishes
2022年更新:现在也有一个slice_head(., n=1)函数。 - dcsuka

30

为了完整起见,以下方法也可以使用:

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

不过,我更倾向于使用distinct的解决方案,而且我认为这样做也更快。


14
大多数情况下,最好的解决方案是使用dplyr中的distinct(),正如已经建议的那样。
然而,这里有另一种方法,它使用了dplyr中的slice()函数。
# 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));

3
如果您想查找重复的行,可以使用来自“hablar”的find_duplicates:
library(dplyr)
library(hablar)

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

df %>% find_duplicates()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接