【发布时间】:2015-05-05 16:42:26
【问题描述】:
我在 R 中有一个数据框,其中行代表事件,一列是事件的日期。事件发生的事情由 ID 列描述。所以每个 ID 都有多个条目。
如何过滤数据框以便只保留每个 ID 的最新事件? ID 是整数,日期格式为mm/dd/yyyy。
【问题讨论】:
标签: r
我在 R 中有一个数据框,其中行代表事件,一列是事件的日期。事件发生的事情由 ID 列描述。所以每个 ID 都有多个条目。
如何过滤数据框以便只保留每个 ID 的最新事件? ID 是整数,日期格式为mm/dd/yyyy。
【问题讨论】:
标签: r
你可以试试
library(dplyr)
df %>%
group_by(ID) %>%
slice(which.max(as.Date(date, '%m/%d/%Y')))
df <- data.frame(ID= rep(1:3, each=3), date=c('02/20/1989',
'03/14/2001', '02/25/1990', '04/20/2002', '02/04/2005', '02/01/2008',
'08/22/2011','08/20/2009', '08/25/2010' ), stringsAsFactors=FALSE)
【讨论】:
as.POSIXct 转换为 POSIXct 并按顺序指定格式
which.max 返回它在一个组中遇到的 first 最大值,如果你有重复的日期,你可能会遇到问题。如果您想保留重复的日期,请查看dplyr::slice_max(date, with_ties=TRUE)。
slice_max,还有另一个问题。假设如果你只有一个值并且行数是 10000,with_ties 将打印所有这 10000 行
对于任何解决方案,您不妨先更正您的日期变量,如@akrun 所示:
df$date <- as.Date(df$date, '%m/%d/%Y')
基础 R
df[
tapply(1:nrow(df),df$ID,function(ii) ii[which.max(df$date[ii])])
,]
这使用选择的行号来对数据进行子集化。您可以通过自行运行中间线([]s 之间)来查看选择。
数据表
类似于@rawr 的:
require(data.table)
DT <- data.table(df)
unique(DT[order(date)], by="ID", fromLast=TRUE)
# or
unique(DT[order(-date)], by="ID")
【讨论】:
tapply 解决方案。我不确定我以前是否认识它。
或者你可以订购日期和
df <- data.frame(ID= rep(1:3, each=3), date=c('02/20/1989',
'03/14/2001', '02/25/1990', '04/20/2002', '02/04/2005', '02/01/2008',
'08/22/2011','08/20/2009', '08/25/2010' ), stringsAsFactors=FALSE)
df$date <- as.Date(df$date, '%m/%d/%Y')
## make sure to order by both `ID` and `date` as Frank mentions in comments
## since the dates may be overlapping among IDs
df <- df[with(df, order(ID, date)), ]
1) 选择最后一个
df[cumsum(table(df$ID)), ]
# ID date
# 2 1 2001-03-14
# 6 2 2008-02-01
# 7 3 2011-08-22
2) 或删除重复项
df[!duplicated(df$ID, fromLast = TRUE), ]
# ID date
# 2 1 2001-03-14
# 6 2 2008-02-01
# 7 3 2011-08-22
@akrun 为您带来的这些数据
【讨论】:
order(df$ID,df$date) 更安全,因为IDs 可能不会将日期划分为不重叠的间隔。
这可能是性格缺陷,但我有时会拒绝购买新包裹。 “base R”函数通常可以完成这项工作。在这种情况下,我认为 dplyr 包的价值已经显现出来,因为我偶然发现了一个好的解决方案,因为 ave 函数返回了一个逻辑测试的字符值,我仍然不明白。所以我认为 dplyr 是一个真正的宝石。如果可以的话,我想坚持在任何赞成票之前都对 akrun 的回答表示赞成票。 (很难相信这个问题还没有在 SO 上被询问和回答。)
无论如何:
> df[ as.logical(
ave(df$date, df$ID, FUN=function(d) as.Date(d , '%m/%d/%Y') ==
max(as.Date(d, '%m/%d/%Y'))))
, ]
ID date
2 1 03/14/2001
6 2 02/01/2008
7 3 08/22/2011
我认为这应该可行(失败):
> df[ ave(df$date, df$ID, FUN=function(d) as.Date(d , '%m/%d/%Y') ==max(as.Date(d, '%m/%d/%Y'))) , ]
ID date
NA NA <NA>
NA.1 NA <NA>
NA.2 NA <NA>
NA.3 NA <NA>
NA.4 NA <NA>
NA.5 NA <NA>
NA.6 NA <NA>
NA.7 NA <NA>
NA.8 NA <NA>
这是另一个基本的 R 解决方案,第一次运行没有任何意外:
> do.call( rbind, by(df, df$ID, function(d) d[ which.max(as.Date(d$date, '%m/%d/%Y')), ] ) )
ID date
1 1 03/14/2001
2 2 02/01/2008
3 3 08/22/2011
这是受@rawr 从有序子集中获取最后一个概念的启发:
> do.call( rbind, by(df, df$ID, function(d) tail( d[ order(as.Date(d$date, '%m/%d/%Y')), ] ,1)) )
ID date
1 1 03/14/2001
2 2 02/01/2008
3 3 08/22/2011
【讨论】:
ave 不喜欢以正确的模式报告结果。这些都不符合逻辑:ave(c("a","b"),1,FUN=function(x)x==x[1]) 或 ave(c(1,2),1,FUN=function(x)x==x[1])
没有plyr,我从来没有在R中处理过任何数据!
library(plyr)
ddply(df, .(ID), summarize, most_recent = max(as.Date(date, '%m/%d/%Y')))
ID most_recent
1 1 2001-03-14
2 2 2008-02-01
3 3 2011-08-22
【讨论】: