多列计算和按多个因素级别聚合值的计算

3

我的数据长这样:

df <- data.frame(Price=seq(1, 1.5, 0.1),
                 Sales=seq(6, 1, -1),
                 Quality=c('A','A','A','B','B','B'),
                 Brand=c('F','P','P','P','F','F'))

有时我需要在多个列上进行复杂的计算,并按多个因素级别聚合值。以一个简化的例子来说,如果我想要得到每个 Quality 中按 Brand 分割的 Revenue(= Price * Sales) 分布情况,我会这样做:
df$Revenue <- df$Price*df$Sales

RevSumByQ <- aggregate(Revenue~Quality, data=df, sum)
colnames(RevSumByQ)[2] <- "RevSumByQ"
df <- merge(df, RevSumByQ)

RevSumWithinQByB <- aggregate(RevSumByQ~Brand, data=df, sum)
colnames(RevSumWithinQByB)[2] <- "RevSumWithinQByB"
df <- merge(df, RevSumWithinQByB)

df$RevDistWithinQByB = df$RevSumByQ/df$RevSumWithinQByB
df

  Brand Quality Price Sales Revenue RevSumByQ RevSumWithinQByB RevDistWithinQByB
1     F       A   1.0     6     6.0      16.3             32.7         0.4984709
2     F       B   1.4     2     2.8       8.2             32.7         0.2507645
3     F       B   1.5     1     1.5       8.2             32.7         0.2507645
4     P       A   1.1     5     5.5      16.3             40.8         0.3995098
5     P       A   1.2     4     4.8      16.3             40.8         0.3995098
6     P       B   1.3     3     3.9       8.2             40.8         0.2009804

如果在绘图中显示:

require(ggplot2)
ggplot(data=df, aes(x=Brand, y=RevDistWithinQByB, fill=Quality)) + geom_bar(stat='identity')

在此输入图片描述

应该有更好的方法来绘制这个图,但我主要关心的是获取数据框(Revenue, RevSumByQ, RevSumWithinQByB)时中间结果较少。我可以看到我的方法中存在一些结构,所以我想知道是否有更优雅的解决方案或者是否已经有一些函数可以简化这种任务。

3个回答

3
你可以尝试使用 dplyr
res <- df %>%
         group_by(Quality) %>% 
         mutate(Revenue= Price*Sales,RevSumByQ=sum(Revenue)) %>% 
         group_by(Brand) %>% 
         mutate(RevSumWithinQByB= sum(RevSumByQ),
             RevDistWithinQByB= RevSumByQ/RevSumWithinQByB ) 

1
你可以将第一个mutate简化为:mutate(RevSumByQ=sum(Price*Sales)) %>%,因为之后不再需要Revenue。 - talat
@docendodiscimus 是的,我确实考虑过那个问题,但是我想也许原帖作者需要那一列来做些什么... :-) - akrun
好的,我明白你的意思。 - talat

2

以下是使用 data.table 的方法:

library(data.table)
setDT(df)
##
df[,Revenue:=Price*Sales][
  ,RevSumByQ:=sum(Revenue),
  by=Quality][
    ,RevSumWithinQByB:=sum(RevSumByQ),
    by=Brand][
      ,RevDistWithinQByB:=RevSumByQ/RevSumWithinQByB]

虽然我通常不这样做,但你可以从同一对象中调用你的ggplot代码:

df[,Revenue:=Price*Sales][
  ,RevSumByQ:=sum(Revenue),
  by=Quality][
    ,RevSumWithinQByB:=sum(RevSumByQ),
    by=Brand][
      ,RevDistWithinQByB:=RevSumByQ/RevSumWithinQByB][
        ,{print(ggplot(
            data=.SD,
            aes(x=Brand,
                y=RevDistWithinQByB,
                fill=Quality))+
            geom_bar(stat="identity"))}]

2

基本上(如@arun所述),您不需要在此处进行合并,并且可以使用基本R中的ave来完成所有操作。似乎很难跳过前两个聚合步骤。虽然您可以跳过最后一个计算并将其直接放入ggplot中。例如:

df$Revenue <- df$Price*df$Sales
df$RevSumByQ <- with(df, ave(Revenue, Quality, FUN = sum))
df$RevSumWithinQByB <- with(df, ave(RevSumByQ, Brand, FUN = sum))

require(ggplot2)
ggplot(data = df, 
       aes(x = Brand, y = RevSumByQ/RevSumWithinQByB, fill = Quality)) +
       geom_bar(stat = 'identity')

enter image description here


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接