dplyr:在 group_by 之后汇总内部的管道

Posted

技术标签:

【中文标题】dplyr:在 group_by 之后汇总内部的管道【英文标题】:dplyr: pipes inside of summarize after group_by 【发布时间】:2016-09-25 17:24:36 【问题描述】:

我有这个data.frame:

df_test = structure(list(`MAE %` = c(-0.0647202646339709, -0.126867775585001, 
-1.81159420289855, -1.03092783505155, -2.0375491194877, -0.160783192796913, 
-0.585827216261999, -0.052988554472234, -0.703351261894911, -0.902996305924203, 
-0.767676767676768, -0.0101091791346543, -0.0134480903711673, 
-0.229357798165138, -0.176407935028625, -0.627062706270627, -1.75706139769261, 
-1.23024009524439, -0.257391763463569, -0.878347259688137, -0.123613523987705, 
-1.65711947626841, -2.11718534838887, -0.256285931980328, -1.87152777777778, 
-0.0552333609500138, -0.943983402489627, -0.541095890410959, 
-0.118607409474639, -0.840453845076341), Profit = c(7260, 2160, 
-7080, 3600, -8700, 6300, -540, 10680, -1880, -3560, -720, 5400, 
5280, 1800, 11040, -240, -2320, 2520, 10300, -2520, 8400, -9240, 
-5190, 7350, -6790, 3600, -3240, 8640, 7150, -2400)), .Names = c("MAE %", 
"Profit"), row.names = c(NA, 30L), class = "data.frame")

现在我想要一些汇总统计数据,例如:

df_test %>% 
    group_by(win.g = Profit > 0) %>%
    summarise(GroupCnt  = n(),
              TopMAE    = filter(`MAE %` > -1) %>% sum(Profit),
              BottomMAE = filter(`MAE %` <= -1) %>% sum(Profit))

因此,如果利润 > 0 或 -1 的行的利润 sum()。 TopMAE、BottomMAE计算必须使用分组。

预期结果如下:

#  win.g CroupCnt TopMAE BottomMAE
#1 FALSE       14 -15100    -39320
#2  TRUE       16  95360      6120

但是我的 R 代码不起作用。我有一个错误:

错误:没有适用于“过滤器”的方法应用于“逻辑”类的对象

我已根据错误更改了我的代码:

df_test %>% 
    group_by(win.g = Profit > 0) %>%
    summarise(UnderStop = n(),
              TopMAE    = filter(., `MAE %` > -1) %>% sum(Profit),
              BottomMAE = filter(., `MAE %` <= -1) %>% sum(Profit))

但结果是没有。我又报错了:

错误:长度不正确 (14),预期:16

我试图了解分组行为以及如何在分组后在汇总中使用管道,但我没有成功。花一整天的时间。

如何获得我的预期结果表?在对这些组进行分组和计算某些函数时,请帮助我理解 dplyr 逻辑。

【问题讨论】:

【参考方案1】:

这就是你要找的吗? (只问是因为我得到的结果与你的输出不同),

df_test %>% 
       group_by(win.g = Profit > 0) %>% 
       summarise(CroupCnt = n(), TopMAE = sum(Profit[`MAE %` > -1]), 
                                 BottomMAE = sum(Profit[`MAE %` <= -1]))

#Source: local data frame [2 x 4]

#  win.g CroupCnt TopMAE BottomMAE
#  (lgl)    (int)  (dbl)     (dbl)
#1 FALSE       14 -15100    -39320
#2  TRUE       16  95360      6120

【讨论】:

感谢您的解决方案。它确实可读且快速。我现在看到的预期数字是错误的。已在我的帖子中纠正了这一点。 @Benjamin 也为我们提供了非常好的解决方案,并且更具 dplyr 风格。我投票给你,因为你是第一个。但是里面的管道汇总和变异等等呢?有没有可能?【参考方案2】:

就个人而言,我更喜欢处理这样的问题,因为您认识到您正在二维上执行分组操作,但您的代码只使用一维。这是一个在两个维度上执行相同工作的示例。它比@Sotos 提供的代码多一点,但提供的结果与他得到的相同。

library(dplyr)
library(tidyr)

df_test %>%
  #* Group on two dimensions
  group_by(win.g = Profit > 0,
           top = ifelse(`MAE %` > -1, "TopMAE", "BottomMAE")) %>%
  summarise(GroupCnt = n(),
            SumProfit = sum(Profit)) %>%
  ungroup() %>%

  #* Collapse the GroupCnt
  group_by(win.g) %>%
  mutate(GroupCnt = sum(GroupCnt)) %>%
  ungroup() %>%

  #* From long to wide
  spread(top, SumProfit)

【讨论】:

不确定结果,因为它们与 OP 的预期结果不同,但如果你得到相同的结果,那么我猜它是真的 在看到您的回答之前,我也有点担心。对于它的价值,我发现在这个例子中你的答案大约是我的两倍。当我将它扩展到 1000 行时,它快了四倍。 (2 对 4 毫秒)。如果我要使用非常大的数据集,我可能会转换为您的答案。 也谢谢你!非常好的 dplyr 样式示例。您向我展示了使用 dplyr 的新方法。我想我们可以省略两个 ungroup() 和一个 group_by() 同时总结一个分组级别的剥离:)。它将更少的代码和更快的速度。但是里面的管道汇总和变异等等呢?有没有可能?

以上是关于dplyr:在 group_by 之后汇总内部的管道的主要内容,如果未能解决你的问题,请参考以下文章

当我在`dplyr`之后加载`plyr`时,为啥汇总或变异不适用于group_by?

使用 dplyr、group_by 和折叠或汇总连接字符串/行,但保持 NA 值 [重复]

R语言dplyr包获取dataframe分组聚合汇总统计值实战(group_by() and summarize() ):均值中位数分位数IQRMADcountunique

在 R 中使用 dplyr 在 group_by 之后应用自定义函数

R语言使用dplyr包聚合(group_by)数据并过滤(fiter)之后再拆开聚合数据(ungroup取消组合)使用ggplot2可视化拆开分组后的线图(line plot)

用dplyr汇总后如何执行计算?