【问题标题】:Cumulative sum based on certain conditions基于特定条件的累计金额
【发布时间】:2015-09-09 10:58:29
【问题描述】:

这是我的数据框:

       X   Y  Date   Qty  CumSumA  CumSumB
    1  A   B   1/1     1        1        0
    2  A   A   1/1     2        3        2
    3  A   E   1/1     2        5        2
    4  B   A   1/1     1        1        1
    5  B   B   1/1     3        4        4
    6  B   C   1/1     2        6        4
    7  C   D   1/1     2        2        2
    8  C   E   1/1     4        6        2
    9  C   A   1/1     1        7        2
   10  A   C   1/2     2        2        0
   11  A   D   1/2     3        5        0
   12  A   E   1/2     2        7        0
   13  B   A   1/2     5        5        0
   14  B   B   1/2     1        6        1
   15  B   C   1/2     2        8        1
   16  C   D   1/2     2        2        4
   17  C   E   1/2     1        1        4
   18  C   A   1/2     3        4        4

我用

得到 CumSumA 列
library(dplyr)
data <- data %>% 
        group_by(Date,X) %>% 
        mutate(CumSumA= cumsum(Qty)) 

我怎样才能得到 CumSumB 列,它是上面所有行的 Qty 的累积总和,在列 @987654326 中具有 (a) 相同的 Date 值和 (b) 相同的行 X 值@。

例如,第 16 行的 X 值为 C,Date 值为 1/2。我想获得 Y 值 C 和 Date 值 1/2 的所有行的 Qty 的累积总和。所以这将是第 10 行加上第 15 行,所以 CumSumB 是 2 + 2 = 4。

请注意,X 和 Y 列有 140 多个唯一变量。

【问题讨论】:

    标签: r dplyr


    【解决方案1】:

    此解决方案基于data.table 并与allow.cartesian=TRUE 结合

    require(data.table)
    setDT(DT)
    

    创建一个基础data.table,我们稍后将使用它的X 列。

    DT_X <- DT[,.(X,Y, Date, indx = .I)]
    setkey(DT_X, Date, X)
    

    删除X 并在原始DT 中插入索引

    DT[,`:=`(X=NULL, indy = .I)]
    setkey(DT, Date, Y)
    

    如果X = Y(与allow.cartesian=TRUE),则加入数据。如果您好奇,请查看DT_join。请参阅 Why does X[Y] join of data.tables not allow a full outer join, or a left join? 为什么这是一个连接

    DT_join <- DT_X[DT, allow.cartesian=TRUE]
    

    indy&lt;=indx 是一个标识符,只取你所说的“上面所有行”的总和。

    DT_join[!is.na(Y), .(CumSumB=sum(Qty * (indy<=indx))), by=.(X,Y,Date)]
    

    编辑(根据 aosmith 回答):也可以使用 by=indx 代替 by=.(X,Y,Date)

    结果:

        X Y Date CumSumB
     1: A B  1/1       0
     2: A A  1/1       2
     3: A E  1/1       2
     4: B A  1/1       1
     5: B B  1/1       4
     6: B C  1/1       4
     7: C D  1/1       2
     8: C E  1/1       2
     9: C A  1/1       2
    10: A C  1/2       0
    11: A D  1/2       0
    12: A E  1/2       0
    13: B A  1/2       0
    14: B B  1/2       1
    15: B C  1/2       1
    16: C D  1/2       4
    17: C E  1/2       4
    18: C A  1/2       4
    

    【讨论】:

    • 非常好,也许也可以添加一些解释
    【解决方案2】:

    这是一个基于 dplyr 的答案,使用与 @Floo0 相同的逻辑。当您拥有更多组时,这往往会变慢。

    首先,我将行号作为一列添加到原始数据集中。 CumSumB 的计算将使用这种方法对每个唯一行进行。

    library(dplyr)
    
    dat = dat %>% mutate(row = row_number())
    

    然后我将数据集加入到自身中,将X 加入到YDate。为了避免添加后缀的许多重复列,我只为连接的x 数据集选择了一些列(即left_join 的第一个数据集)。

    我故意将变量row 保留在两个数据集中,因此我最终得到一个名为row.x 的变量,它指示每个X 值的原始行号和一个名为row.y 的变量,指示原始行每个Y 值的数量。

    dat %>% 
        left_join(select(dat, X, Date, Y, row), ., by  = c("X" = "Y", "Date" = "Date"))
    

    完成后,只需将数据集按row.x 分组,并以row.x 小于或等于row.y 为条件计算Qty 的总和。

    dat %>% 
        left_join(select(dat, X, Date, Y, row), ., by  = c("X" = "Y", "Date" = "Date")) %>%
        group_by(row.x) %>%
        summarise(CumSumB = sum(Qty[row.y <= row.x]))
    

    最后,这可以连接回原始数据集。结果仍然包含表示行号的列,如果需要,可以通过select(-row) 删除。

    dat %>% 
        left_join(select(dat, X, Date, Y, row), ., by  = c("X" = "Y", "Date" = "Date")) %>%
        group_by(row.x) %>%
        summarise(CumSumB = sum(Qty[row.y <= row.x])) %>%
        left_join(dat, ., by = c("row" = "row.x"))
    
       X Y Date Qty CumSumA CumSumB.x row CumSumB.y
    1  A B  1/1   1       1         0   1         0
    2  A A  1/1   2       3         2   2         2
    3  A E  1/1   2       5         2   3         2
    4  B A  1/1   1       1         1   4         1
    5  B B  1/1   3       4         4   5         4
    6  B C  1/1   2       6         4   6         4
    7  C D  1/1   2       2         2   7         2
    8  C E  1/1   4       6         2   8         2
    9  C A  1/1   1       7         2   9         2
    10 A C  1/2   2       2         0  10         0
    11 A D  1/2   3       5         0  11         0
    12 A E  1/2   2       7         0  12         0
    13 B A  1/2   5       5         0  13         0
    14 B B  1/2   1       6         1  14         1
    15 B C  1/2   2       8         1  15         1
    16 C D  1/2   2       2         4  16         4
    17 C E  1/2   1       1         4  17         4
    18 C A  1/2   3       4         4  18         4
    

    【讨论】:

    • +1 干得好!我喜欢你按row.x 分组的想法,因为这比我按X, YDate 分组更短更容易。
    猜你喜欢
    • 2017-08-01
    • 1970-01-01
    • 2016-03-27
    • 1970-01-01
    • 2017-09-28
    • 2022-10-25
    • 2023-03-15
    • 2021-04-21
    • 2021-03-15
    相关资源
    最近更新 更多