【问题标题】:Filter dataframe by maximum values in each group [duplicate]按每组中的最大值过滤数据帧[重复]
【发布时间】:2015-02-16 12:20:56
【问题描述】:

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

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

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

我首先尝试在sapply() 中使用which() 循环idsifelse() 语句,这非常慢(我相信O(n^2))。

然后我尝试按iddf 进行排序,然后以两个为增量循环并比较相邻日期,但这也很慢(我猜是因为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),]

跑得很快!!

【问题讨论】:

    标签: r dataframe filtering


    【解决方案1】:

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

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

    或者(由于 keyed by

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

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

    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
    

    【讨论】:

    • 答案中的 dplyr 选项为小样本数据产生相同的输出,但对于其他数据,每个数据的行为可能不同:filter 将保留所有现有列,但允许多行以防出现平局; slice 将保留所有列,但不会返回多行以防出现平局; summarise 将删除所有其他列,并且在出现平局时不会返回多行。就像以后看到这个的人的信息一样..
    • @docendodiscimus 这些都是很棒的观察。您可以作为我的dplyr guru 将这些解释添加到我的解决方案中
    • 好吧,我已经在 cmets 中添加了它们,所以没有必要将它放在答案中。 :)
    • @docendodiscimus,好的,已添加。
    【解决方案2】:

    聚合也应该起作用:

    aggregate(date ~ id, df, max)
    

    【讨论】:

    • 虽然对于大数据集来说会非常非常慢...
    • 实际上在我的破笔记本电脑@DavidArenburg 上需要 1.5 秒。您的基本解决方案需要
    • @rawr 的数据大小是多少?
    • dat data.frame 578922376 552.1 Mb 180000 402
    猜你喜欢
    • 1970-01-01
    • 2021-10-25
    • 1970-01-01
    • 2018-01-14
    • 2021-09-09
    • 1970-01-01
    • 2019-11-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多