R :: data.table:使用先前的余额和按行迭代按组生成运行余额

Jan*_* Lu 6 iteration row r data.table

我在R中关注了DT(data.table)。

dt <- fread("
id| rowids | charge | payment | balance
a |   1    |  7.1   |   0     |     
a |   2    |  1.2   |   3     |   
a |   3    |  1.7   |   1     |   
b |   1    |  8.1   |   0     |   
b |   2    |  2.5   |   4     |   
b |   3    |  2.3   |   2     |   
b |   4    |  3.2   |   1     |   
            ", 
            sep = "|",
            colClasses = c("character", "numeric", "numeric", "numeric", 
"numeric"))
Run Code Online (Sandbox Code Playgroud)

应该在每个id组中将“余额”计算为“余额<-previous.row.balance +费用-付款”,其中“ previous.row.balance”是“ balance”的上一行条目。

我最初低估了计算平衡的难度。我在想dt[,previous.row.balance := (shift(balance,1),by=id]。但是R确实进行了矢量化计算。我没有“ balance”中的值可用于执行shift(),因为“ balance”将通过逐行迭代进行计算。

我搜索了StackOverflow,发现了一个类似的问题,它的第一个答案极大地帮助我思考了整个过程。我对问题的第一个答案改编了代码,并使以下代码出色地工作以按组生成运行平衡。

dt[rowids == 1, balance := charge, by=.(id)]
dt[rowids != 1, balance :=
    dt[,
        {
            balance1 <- balance[1L]
            .SD[rowids != 1,
                {balance1 <-  balance1 + charge - payment
                    .(balance1)
                },
                by=.(rowids)]
        },
        by=.(id)][, -1L:-2L]
]
Run Code Online (Sandbox Code Playgroud)

这是我的问题。

  1. 我仍然不明白如何by=.(id)][, -1L:-2L],链式括号解决了迭代问题。由于该代码未使用shift() by = group,因此我猜想[, -1L:-2L]这里有技巧可以执行迭代。但是如何?什么是[, -1L:-2L]真正在这里做?

抱歉,我必须在这里提出这个问题,而不是在该问题下发表评论或提出问题。原因是我是StackOverflow的新手,仅获得1点声誉。我不允许对这个问题的原始答案发表评论。我也想投票赞成这个答案。在我这样做之前,我必须获得更多积分。

  1. 还有其他方法,可以使用data.table和R向量化计算来实现此运行平衡目标,而无需为行迭代包装任何循环?

任何见解或想法都将受到赞赏!

Ice*_*can 4

关于你的问题#2:

您可以使用该cumsum函数(输出与问题中的代码匹配)。charge - payment这将采用第一行的值,然后对于第二行,第二行将charge - payment添加到该值,依此类推。

dt[, balance2 := cumsum(charge - payment), id]


dt
#    id rowids charge payment balance balance2
# 1:  a      1    7.1       0     7.1      7.1
# 2:  a      2    1.2       3     5.3      5.3
# 3:  a      3    1.7       1     6.0      6.0
# 4:  b      1    8.1       0     8.1      8.1
# 5:  b      2    2.5       4     6.6      6.6
# 6:  b      3    2.3       2     6.9      6.9
# 7:  b      4    3.2       1     9.1      9.1
Run Code Online (Sandbox Code Playgroud)