如何删除R数据帧中除一个特定的重复记录以外的所有记录?[关闭]


16

我有一个包含一些重复ID的数据框。我想删除具有重复ID的记录,仅保留具有最大值的行。

因此对于这样的结构(其他变量未显示):

id var_1
1 2
1 4
2 1
2 3
3 5
4 2

我想生成这个:

id var_1
1 4
2 3
3 5
4 2

我知道unique()和重复的(),但我不知道如何合并最大化规则...


它实际上应该是在计算器,因为它是一个纯粹的编程相关的任务,并没有什么用统计做
发烧友

Answers:


24

一种方法是对数据进行反向排序,然后使用duplicated它删除所有重复项。对我而言,此方法在概念上比使用apply方法更简单。我认为它也应该非常快。

# Some data to start with:
z <- data.frame(id=c(1,1,2,2,3,4),var=c(2,4,1,3,5,2))
# id var
#  1   2
#  1   4
#  2   1
#  2   3
#  3   5
#  4   2

# Reverse sort
z <- z[order(z$id, z$var, decreasing=TRUE),]
# id var
#  4   2
#  3   5
#  2   3
#  2   1
#  1   4
#  1   2

# Keep only the first row for each duplicate of z$id; this row will have the
# largest value for z$var
z <- z[!duplicated(z$id),]

# Sort so it looks nice
z <- z[order(z$id, z$var),]
# id var
#  1   4
#  2   3
#  3   5
#  4   2

编辑:我只是意识到上面的反向排序根本不需要排序id。您可以只使用z[order(z$var, decreasing=TRUE),]它,它也可以正常工作。

再想一想...如果该var列是数字列,则有一种简单的排序方式,使之id递增,但var递减。这样就无需在末尾进行排序(假设您甚至希望对其进行排序)。

z <- data.frame(id=c(1,1,2,2,3,4),var=c(2,4,1,3,5,2))

# Sort: id ascending, var descending
z <- z[order(z$id, -z$var),]

# Remove duplicates
z <- z[!duplicated(z$id),]
# id var
#  1   4
#  2   3
#  3   5
#  4   2

1
这种方法比“ split-compute-rbind”要快得多。此外,它允许对多个因素进行分组。对于一个 650,000行(8行,窄,列)的“订单重复”方法花费了55秒,而split-compute-rbind ...花费了1h15分钟。当然,当聚集计算不是选择或过滤重复项时,则需要后一种方法或类似的基于plyr的方法。
mjv 2014年

7

您实际上想从具有相同ID的元素中选择最大元素。为此,您可以使用plyrddply软件包:

> dt<-data.frame(id=c(1,1,2,2,3,4),var=c(2,4,1,3,4,2))
> ddply(dt,.(id),summarise,var_1=max(var))
   id var_1
1  1   4
2  2   3
3  3   4
4  4   2

unique并且duplicated用于删除重复的记录,在您的情况下,您只有重复的ID,而没有记录。

更新:这是有其他变量时的代码:

> dt<-data.frame(id=c(1,1,2,2,3,4),var=c(2,4,1,3,4,2),bu=rnorm(6))
> ddply(dt,~id,function(d)d[which.max(d$var),])

如果还有其他变量,该怎么办:如何携带它们?
兄子

我们不会提出这样的问题-太着急而得不到太多收益。

6

base-R解决方案将涉及split,如下所示:

z<-data.frame(id=c(1,1,2,2,3,4),var=c(2,4,1,3,4,2))
do.call(rbind,lapply(split(z,z$id),function(chunk) chunk[which.max(chunk$var),]))

split将数据帧拆分为一个大块列表,在该列表上,我们将数据切割为具有最大值的单行,然后do.call(rbind,...)将单行列表再次缩小为一个数据帧。


1
和往常一样,这比plyr版本快2倍。

1
@mbq,是的,很自然,但是如果包括调试成本,对于通常的数据集,所得的速度是相同的:) plyr并不是为了速度而是为了清晰和方便。
mpiktas 2011年

并且使用ave的速度快一倍:)
Eduardo Leoni

2
@Eduardo avelapply+ 的包装split,请检查代码(-;

1
@Eduardo是的,但是所有这些都只能通过在使用的因素内进行矢量化排序的可能性来实现order。对于更多的通用问题split是不可避免的。

5

我更喜欢使用 ave

dt<-data.frame(id=c(1,1,2,2,3,4),var=c(2,4,3,3,4,2))
## use unique if you want to exclude duplicate maxima
unique(subset(dt, var==ave(var, id, FUN=max)))

+1,不知道ave。它何时出现在R中?
mpiktas 2011年

1

使用base的另一种方法是:

dt<-data.frame(id=c(1,1,2,2,3,4),var=c(2,4,1,3,4,2))

data.frame(id=sort(unique(dt$var)),max=tapply(dt$var,dt$id,max))
  id max
1  1   4
2  2   3
3  3   4
4  4   2

我更喜欢mpiktas的plyr解决方案。


1

如示例中所示,如果列var已经按升序排列,则不需要对数据框进行排序。我们只使用duplicated传递参数的函数fromLast = TRUE,因此从反面考虑重复,并保留最后一个元素:

z <- data.frame(id=c(1,1,2,2,3,4),var=c(2,4,1,3,5,2))
z[!duplicated(z$id, fromLast = TRUE), ]

  id var
2  1   4
4  2   3
5  3   5
6  4   2

否则,我们将首先按升序对数据框进行排序:

z <- z[order(z$id, z$var), ]
z[!duplicated(z$id, fromLast = TRUE), ]

使用dplyr包装:

library(dplyr)
z %>%
  group_by(id) %>%
  summarise(var = max(var))

Source: local data frame [4 x 2]    
  id var
1  1   4
2  2   3
3  3   5
4  4   2
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.