13

如果这更容易,我需要在 ddply 或聚合的级别中使用 group by。我不确定如何执行此操作,因为我需要使用 cumsum 作为我的聚合函数。这是我的数据的样子:

level1      level2  hour     product 
A           tea     0          7
A           tea     1          2
A           tea     2          9
A           coffee  17         7
A           coffee  18         2
A           coffee  20         4
B           coffee  0          2
B           coffee  1          3
B           coffee  2          4
B           tea     21         3
B           tea     22         1

预期输出:

A     tea     0   7
A     tea     1   9
A     tea     2   18
A     coffee  17  7
A     coffee  18  9
A     coffee  20  13
B     coffee  0   2
B     coffee  1   5
B     coffee  2   9
B     tea     21  3
B     tea     22  4

我尝试使用

ddply(dd,c("level1","level2","hour"),summarise,cumsum(product))

但这并没有总结起来,我认为这是因为小时列被用于分组,并且被它分割..我认为..我不确定我是否完全理解聚合在这里是如何工作的。有什么方法可以使用聚合或 ddply 获得所需的输出?

4

3 回答 3

16

ave这是使用and的基础 R 中的解决方案within

within(mydf, {
  cumsumProduct <- ave(product, level1, level2, FUN = cumsum)
})
#    level1 level2 hour product cumsumProduct
# 1       A    tea    0       7             7
# 2       A    tea    1       2             9
# 3       A    tea    2       9            18
# 4       A coffee   17       7             7
# 5       A coffee   18       2             9
# 6       A coffee   20       4            13
# 7       B coffee    0       2             2
# 8       B coffee    1       3             5
# 9       B coffee    2       4             9
# 10      B    tea   21       3             3
# 11      B    tea   22       1             4

当然,如果您想删除现有的产品列,您可以将命令更改为以下内容以覆盖当前的“产品”列:

within(mydf, {
  product <- ave(product, level1, level2, FUN = cumsum)
})

您当前的方法部分不起作用,因为您已将“小时”作为分组变量之一。换句话说,它看到“A + tea + 0”的组合与“A + tea + 1”不同,但从您想要的输出来看,您似乎只是希望“A + tea”的组合成为团体。

aggregate不会像您期望的那样工作,因为它会将所有内容压缩data.frame成行数与“level1”和“level2”的唯一组合数相同的行数,在本例中为 4 行。聚合列将是一个list. 这些值是正确的,但用处不大。

这是aggregate及其输出:

> aggregate(product ~ level1 + level2, mydf, cumsum)
  level1 level2  product
1      A coffee 7, 9, 13
2      B coffee  2, 5, 9
3      A    tea 7, 9, 18
4      B    tea     3, 4
于 2013-02-21T10:21:30.883 回答
7

你应该使用transform而不是summarise

# you should probably order your `level2` first
dd$level2 <- factor(dd$level2, levels=c("tea", "coffee"))
# and transform using level1 and level2 alone, not hour
# if you use hour, the groups will be for each row
ddply(dd, .(level1, level2), transform, product=cumsum(product))

#    level1 level2 hour product
# 1       A    tea    0       7
# 2       A    tea    1       9
# 3       A    tea    2      18
# 4       A coffee   17       7
# 5       A coffee   18       9
# 6       A coffee   20      13
# 7       B    tea   21       3
# 8       B    tea   22       4
# 9       B coffee    0       2
# 10      B coffee    1       5
# 11      B coffee    2       9
于 2013-02-21T10:19:42.330 回答
0

现在引用此内容的人们可能希望避免使用plyr::ddply. 这是一个dplyr解决方案。

library(dplyr)
output <- dd %>%
  group_by(level1, level2) %>%
  mutate(product_sum = cumsum(product)) %>%
  ungroup()
output

请注意,这product_sum是新列的命名位置。你可以product改用。然后,原始产品列将被覆盖,因为看起来原始问题可能更愿意这样做并且在输出中没有两列。

数据:

level1 <- c(rep("A",6), rep("B",5))
level2 <- c(rep("tea",3), rep("coffee",6), rep("tea",2))
hour <- c(0,1,2,17,18,20,0,1,2,21,22)
product <- c(7,2,9,7,2,4,2,3,4,3,1)

dd <- data.frame(level1, level2, hour, product)
于 2022-02-24T17:01:23.810 回答