按每组中的最大值过滤数据帧

时间:2014-12-17 20:29:02

标签: r dataframe filtering

我有一个180,000 x 400的数据框,其中行对应于用户,但每个用户只有两行。

id   date  ...
1    2012    ...
3    2010    ...
2    2013    ...
2    2014    ...
1    2011    ...
3    2014    ...

我希望对数据进行子集化,以便仅保留每个用户的最新行(即每个ID的日期值最高的行)。

我首先尝试在which()中使用ids循环ifelse()sapply()语句,但速度非常缓慢(我相信O(n^2))。

然后我尝试按df排序id,然后以2为增量循环并比较相邻日期,但这也很慢(我猜因为R中的循环是没有希望的)。两个日期的比较是瓶颈,因为排序几乎是即时的。

有没有办法对比较进行矢量化?

来自Remove duplicates keeping entry with largest absolute value

的解决方案
aa <- df[order(df$id, -df$date), ] #sort by id and reverse of date
aa[!duplicated(aa$id),]

跑得很快!!

2 个答案:

答案 0 :(得分:22)

这是使用data.table包

的一种简单快捷的方法
library(data.table)
setDT(df)[, .SD[which.max(date)], id]
#    id date
# 1:  1 2012
# 2:  3 2014
# 3:  2 2014

或者(由于键入 by

,可能会快一点
setkey(setDT(df), id)[, .SD[which.max(date)], id]

或通过data.table

使用OP的想法
unique(setorder(setDT(df), id, -date), by = "id")

或者

setorder(setDT(df), id, -date)[!duplicated(id)]

或基础R解决方案

with(df, tapply(date, id, function(x) x[which.max(x)]))
##    1    2    3 
## 2012 2014 2014 

另一种方式

library(dplyr)
df %>%
  group_by(id) %>%
  filter(date == max(date)) # Will keep all existing columns but allow multiple rows in case of ties
# Source: local data table [3 x 2]
# Groups: id
# 
#   id date
# 1  1 2012
# 2  2 2014
# 3  3 2014

或者

df %>%
  group_by(id) %>%
  slice(which.max(date)) # Will keep all columns but won't return multiple rows in case of ties

或者

df %>%
  group_by(id) %>%
  summarise(max(date)) # Will remove all other columns and wont return multiple rows in case of ties

答案 1 :(得分:5)

聚合也应该有效:

aggregate(date ~ id, df, max)