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

mat*_*lin 13 filtering r dataframe

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

id   date  ...
1    2012    ...
3    2010    ...
2    2013    ...
2    2014    ...
1    2011    ...
3    2014    ...
Run Code Online (Sandbox Code Playgroud)

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

我首先尝试使用which()循环语句,其中idsifelse()语句sapply()很慢(O(n^2)我相信).

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

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

解决方案来自删除重复项,保持最大绝对值的输入

aa <- df[order(df$id, -df$date), ] #sort by id and reverse of date
aa[!duplicated(aa$id),]
Run Code Online (Sandbox Code Playgroud)

跑得很快!!

Dav*_*urg 25

这是一个使用data.table包的简单快速的方法

library(data.table)
setDT(df)[, .SD[which.max(date)], id]
#    id date
# 1:  1 2012
# 2:  3 2014
# 3:  2 2014
Run Code Online (Sandbox Code Playgroud)

或者(由于键控可能会更快一点 by

setkey(setDT(df), id)[, .SD[which.max(date)], id]
Run Code Online (Sandbox Code Playgroud)

或者通过data.table包使用OPs的想法

unique(setorder(setDT(df), id, -date), by = "id")
Run Code Online (Sandbox Code Playgroud)

要么

setorder(setDT(df), id, -date)[!duplicated(id)]
Run Code Online (Sandbox Code Playgroud)

或者基础R解决方案

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

其他方式

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

要么

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

要么

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


tal*_*lat 5

聚合也应该有效:

aggregate(date ~ id, df, max)
Run Code Online (Sandbox Code Playgroud)

  • 实际上我的笔记本电脑@DavidArenburg需要1.5秒.你的基础解决方案需要<1秒,所以欢呼你 (3认同)