【问题标题】:Select row with most recent date by group按组选择具有最近日期的行
【发布时间】:2015-05-05 16:42:26
【问题描述】:

我在 R 中有一个数据框,其中行代表事件,一列是事件的日期。事件发生的事情由 ID 列描述。所以每个 ID 都有多个条目。

如何过滤数据框以便只保留每个 ID 的最新事件? ID 是整数,日期格式为mm/dd/yyyy

【问题讨论】:

    标签: r


    【解决方案1】:

    你可以试试

    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)
    

    【讨论】:

    • 如何做到这一点,还要考虑小时、分钟和秒?我有一些寄存器具有相同的月、日、年、小时和分钟,但秒数不同,我无法获得最新的。提前致谢。
    • @kikusanchez 您可能需要使用as.POSIXct 转换为 POSIXct 并按顺序指定格式
    • 应该注意的是,因为which.max 返回它在一个组中遇到的 first 最大值,如果你有重复的日期,你可能会遇到问题。如果您想保留重复的日期,请查看dplyr::slice_max(date, with_ties=TRUE)
    • @nstjhp 是的,但是对于slice_max,还有另一个问题。假设如果你只有一个值并且行数是 10000,with_ties 将打印所有这 10000 行
    • @akrun 非常好,只是想提出这个问题,以防它对任何人有所帮助。
    【解决方案2】:

    对于任何解决方案,您不妨先更正您的日期变量,如@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")
    

    【讨论】:

    • 这是一个非常有趣的基础 R tapply 解决方案。我不确定我以前是否认识它。
    【解决方案3】:

    或者你可以订购日期和

    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 可能不会将日期划分为不重叠的间隔。
    • @Frank werd。我以为我做到了,很好。很遗憾它没有这样做,否则我不会抓住它
    【解决方案4】:

    这可能是性格缺陷,但我有时会拒绝购买新包裹。 “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])
    【解决方案5】:

    没有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
    

    【讨论】:

    • 这将返回两列:“ID”和“最近的”。我怎样才能保留其余的列?
    猜你喜欢
    • 2015-06-21
    • 1970-01-01
    • 2012-04-15
    • 2020-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多