【问题标题】:How to do Group By Rollup in R? (Like SQL)如何在 R 中进行分组汇总? (如 SQL)
【发布时间】:2016-07-10 04:58:00
【问题描述】:

我有一个数据集,我想像 SQL 中的聚合值一样执行 Group By Rollup 之类的操作。

以下是一个可重现的示例。我知道 aggregate 的效果非常好,正如 here 所解释的那样,但不适合我的情况。

year<- c('2016','2016','2016','2016','2017','2017','2017','2017')
month<- c('1','1','1','1','2','2','2','2')
region<- c('east','west','east','west','east','west','east','west')
sales<- c(100,200,300,400,200,400,600,800)
df<- data.frame(year,month,region,sales)
df


year month region sales
1 2016     1   east   100
2 2016     1   west   200
3 2016     1   east   300
4 2016     1   west   400
5 2017     2   east   200
6 2017     2   west   400
7 2017     2   east   600
8 2017     2   west   800

现在我要做的是聚合(按年月区域求和)并在现有数据框中添加新的聚合行 例如应该有两个额外的行,如下所示,聚合行的区域新名称为“美国”

year month region sales
1 2016     1   east   400
2 2016     1   west   600
3 2016     1    USA  1000
4 2017     2   east   800
5 2017     2   west  1200
6 2017     2    USA  2000

我已经找到了一种方法(如下),但我很确定存在一个最佳解决方案,或者比我的更好的解决方法

df1<- setNames(aggregate(df$sales, by=list(df$year,df$month, df$region), FUN=sum),
    c('year','month','region', 'sales'))


df2<- setNames(aggregate(df$sales, by=list(df$year,df$month), FUN=sum),
               c('year','month', 'sales'))

df2$region<- 'USA'                  ## added a new column- region- for total USA
df2<- df2[,  c('year','month','region', 'sales')]  ## reordering the columns of df2

df3<- rbind(df1,df2)

df3<- df3[order(df3$year,df3$month,df3$region),]  ## order by
rownames(df3)<- NULL  ## renumbered the rows after order by

df3

感谢支持!

【问题讨论】:

    标签: r data-manipulation rollup


    【解决方案1】:

    在最近开发的 data.table 1.10.5 中,您可以使用称为“分组集”的新功能来生成小计:

    library(data.table)
    setDT(df)
    res = groupingsets(df, .(sales=sum(sales)), sets=list(c("year","month"), c("year","month","region")), by=c("year","month","region"))
    setorder(res, na.last=TRUE)
    res
    #   year month region sales
    #1: 2016     1   east   400
    #2: 2016     1   west   600
    #3: 2016     1     NA  1000
    #4: 2017     2   east   800
    #5: 2017     2   west  1200
    #6: 2017     2     NA  2000
    

    您可以使用res[is.na(region), region := "USA"]NA 替换为USA

    【讨论】:

      【解决方案2】:

      reshape2 包中的melt/dcast 可以进行小计。运行 dcast 后,我们将月份列中的 "(all)" 替换为使用 zoo 包中的 na.locf 的月份:

      library(reshape2)
      library(zoo)
      
      m <- melt(df, measure.vars = "sales")
      dout <- dcast(m, year + month + region ~ variable, fun.aggregate = sum, margins = "month")
      
      dout$month <- na.locf(replace(dout$month, dout$month  == "(all)", NA))
      

      给予:

      > dout
        year month region sales
      1 2016     1   east   400
      2 2016     1   west   600
      3 2016     1  (all)  1000
      4 2017     2   east   800
      5 2017     2   west  1200
      6 2017     2  (all)  2000
      

      【讨论】:

      • 您的答案非常接近,但第 3 行和第 6 行也应填写月份。有什么解决方法吗?
      • 已添加 na.locf 以填充小计行中的月份,还添加了一个 melt 允许 dcast 生成正确的名称而无需稍后修复它们。还删除了似乎不需要的总计。
      • 该死!刚看到你在日记里提到。你是 Zoo 和其他类的创建者。 :)
      【解决方案3】:
      plyr::ddply(df, c("year", "month", "region"), plyr::summarise, sales = sum(sales))
      

      【讨论】:

      • 这是我的示例中 df1 的 o/p(使用聚合),而不是所需的答案。
      猜你喜欢
      • 1970-01-01
      • 2017-06-21
      • 1970-01-01
      • 1970-01-01
      • 2021-12-26
      • 1970-01-01
      • 2021-12-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多