【问题标题】:Aggregate a dataframe on a given column and display another column在给定列上聚合数据框并显示另一列
【发布时间】:2011-09-11 11:37:32
【问题描述】:

我在 R 中有一个如下形式的数据框:

> head(data)
  Group Score Info
1     1     1    a
2     1     2    b
3     1     3    c
4     2     4    d
5     2     3    e
6     2     1    f

我想使用max 函数在Score 列之后聚合它

> aggregate(data$Score, list(data$Group), max)

  Group.1         x
1       1         3
2       2         4

但我还想显示与每个组的 Score 列的最大值相关联的 Info 列。我不知道该怎么做。我想要的输出是:

  Group.1         x        y
1       1         3        c
2       2         4        d

有什么提示吗?

【问题讨论】:

    标签: r aggregate plyr greatest-n-per-group


    【解决方案1】:

    这是使用plyr 包的解决方案。

    以下代码行本质上是告诉ddply 首先按组对您的数据进行分组,然后在每个组中返回一个子集,其中分数等于该组中的最高分数。

    library(plyr)
    ddply(data, .(Group), function(x)x[x$Score==max(x$Score), ])
    
      Group Score Info
    1     1     3    c
    2     2     4    d
    

    而且,正如@SachaEpskamp 指出的那样,这可以进一步简化为:

    ddply(df, .(Group), function(x)x[which.max(x$Score), ])
    

    (它还有一个优点是which.max 将返回多个最大行,如果有的话)。

    【讨论】:

    • which.max(x$Score) 可以用来代替x$Score==max(x$Score)。在此示例中,这运行良好,并且通常更简洁,但当存在多个最大值(并列)时,它并不总是按预期工作。
    【解决方案2】:

    plyr 包可用于此目的。使用ddply() 函数,您可以在一个或多个列上拆分数据框并应用一个函数并返回一个数据框,然后使用summarize() 函数您可以使用拆分数据框的列作为变量来生成新的数据框/;

    dat <- read.table(textConnection('Group Score Info
    1     1     1    a
    2     1     2    b
    3     1     3    c
    4     2     4    d
    5     2     3    e
    6     2     1    f'))
    
    library("plyr")
    
    ddply(dat,.(Group),summarize,
        Max = max(Score),
        Info = Info[which.max(Score)])
      Group Max Info
    1     1   3    c
    2     2   4    d
    

    【讨论】:

    • 很好,但我想你会同意我的解决方案更通用,因为它将返回原始 data.frame 中的所有列。
    • 确实如此。如果您假设每个组只有一个最大值,您可以将 x$Score==max 更改为 which,max
    • 啊,太好了。我不知道which.max
    【解决方案3】:

    基本的 R 解决方案是将aggregate() 的输出与merge() 步骤结合起来。我发现aggregate() 的公式接口比标准接口更有用,部分原因是输出上的名称更好,所以我将使用它:

    aggregate() 步骤是

    maxs <- aggregate(Score ~ Group, data = dat, FUN = max)
    

    merge() 步骤很简单

    merge(maxs, dat)
    

    这给了我们想要的输出:

    R> maxs <- aggregate(Score ~ Group, data = dat, FUN = max)
    R> merge(maxs, dat)
      Group Score Info
    1     1     3    c
    2     2     4    d
    

    当然,您可以将其粘贴到单行中(中间步骤更多用于说明):

    merge(aggregate(Score ~ Group, data = dat, FUN = max), dat)
    

    我使用公式接口的主要原因是它为合并步骤返回了一个带有正确names的数据框;这些是来自原始数据集dat 的列的名称。我们需要让aggregate() 的输出具有正确的名称,以便merge() 知道原始数据帧和聚合数据帧中的哪些列匹配。

    标准接口给出了奇怪的名字,不管你怎么称呼它:

    R> aggregate(dat$Score, list(dat$Group), max)
      Group.1 x
    1       1 3
    2       2 4
    R> with(dat, aggregate(Score, list(Group), max))
      Group.1 x
    1       1 3
    2       2 4
    

    我们可以在这些输出上使用merge(),但我们需要做更多的工作来告诉 R 哪些列匹配。

    【讨论】:

    • 这很好。我玩过base R,但想不出解决方案。我从未想过使用merge
    • 想出这么简洁的答案还为时过早。
    • @Roman 我猜这只是拥有一个 4 个月大的孩子的众多好处之一——即使是更短的睡眠时间也有其好处 ;-)
    • Score 为浮点/双精度时,merge 是否也能可靠工作? IIRC,“平等”对于浮点数来说不是微不足道的。
    • 这个和接受的答案都解决了我的问题。不过,这个更干净一点,IMO。
    【解决方案4】:

    这就是我baseically 思考问题的方式。

    my.df <- data.frame(group = rep(c(1,2), each = 3), 
            score = runif(6), info = letters[1:6])
    my.agg <- with(my.df, aggregate(score, list(group), max))
    my.df.split <- with(my.df, split(x = my.df, f = group))
    my.agg$info <- unlist(lapply(my.df.split, FUN = function(x) {
                x[which(x$score == max(x$score)), "info"]
            }))
    
    > my.agg
      Group.1         x info
    1       1 0.9344336    a
    2       2 0.7699763    e
    

    【讨论】:

      【解决方案5】:

      首先,您使用split 拆分数据:

      split(z,z$Group)
      

      然后,对于每个块,选择得分最高的行:

      lapply(split(z,z$Group),function(chunk) chunk[which.max(chunk$Score),])
      

      最后还原成data.frame do.calling rbind:

      do.call(rbind,lapply(split(z,z$Group),function(chunk) chunk[which.max(chunk$Score),]))
      

      结果:

        Group Score Info
      1     1     3    c
      2     2     4    d
      

      一行,没有魔法,速度快,结果有好名字=)

      【讨论】:

        【解决方案6】:

        一个迟到的答案,但使用data.table的方法

        library(data.table)
        DT <- data.table(dat)
        
        DT[, .SD[which.max(Score),], by = Group]
        

        或者,如果可能有多个相同的最高分

        DT[, .SD[which(Score == max(Score)),], by = Group]
        

        注意到(来自?data.table

        .SD 是一个 data.table,其中包含每个组的 x 数据子集,不包括组列

        【讨论】:

        • 如何只计算最后六个值的标准差,而不是整列的标准差?您是否首先需要聚合数据,或者 R 中是否存在类似 SQL 风格的OVER (PARTITION ... BETWEEN 5 PRECEDING AND CURRENT ROW?我试图回答这个here 但卡住了。
        • @hhh 这看起来像滚动 sd,请点赞github.com/Rdatatable/data.table/issues/2778
        【解决方案7】:

        补充 Gavin 的答案:在合并之前,可以在不使用公式接口时获取聚合以使用专有名称:

        aggregate(data[,"score", drop=F], list(group=data$group), mean) 
        

        【讨论】:

          【解决方案8】:

          我没有足够高的声誉来评论 Gavin Simpson 的回答,但我想警告一下,标准语法和 aggregate 的公式语法之间缺失值的默认处理似乎有所不同.

          #Create some data with missing values 
          a<-data.frame(day=rep(1,5),hour=c(1,2,3,3,4),val=c(1,NA,3,NA,5))
            day hour val
          1   1    1   1
          2   1    2  NA
          3   1    3   3
          4   1    3  NA
          5   1    4   5
          
          #Standard syntax
          aggregate(a$val,by=list(day=a$day,hour=a$hour),mean,na.rm=T)
            day hour   x
          1   1    1   1
          2   1    2 NaN
          3   1    3   3
          4   1    4   5
          
          #Formula syntax.  Note the index for hour 2 has been silently dropped.
          aggregate(val ~ hour + day,data=a,mean,na.rm=T)
            hour day val
          1    1   1   1
          2    3   1   3
          3    4   1   5
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2019-12-18
            • 2019-08-31
            • 2022-07-01
            • 2019-10-27
            • 1970-01-01
            • 1970-01-01
            • 2021-07-24
            相关资源
            最近更新 更多