R:使用上一行的值更新(视情况而定)

use*_*717 5 r data.table

我想更新表中的值,包含组中的上一行的值(并且可能在给定条件下停止更新)

这是一个例子:

set.seed(12345)

field <- data.table(time=1:3, player = letters[1:2], prospects = round(rnorm(6),2))
setkey(field, player, time)
field[time == 1, energy := round(rnorm(2),2)] #initial level - this is what I want to propagate down the table
#let 'prospects < 0.27' be the condition that stops the process, and sets 'energy = 0'
#player defines the groups within which the updates are made
Run Code Online (Sandbox Code Playgroud)

这是我的桌子.

> field
time player prospects energy
1:    1      a      0.81  -0.32
2:    2      a      0.25     NA
3:    3      a      2.05     NA
4:    1      b      1.63  -1.66
5:    2      b      2.20     NA
6:    3      b      0.49     NA
Run Code Online (Sandbox Code Playgroud)

这是我想要的表.

> field
time player prospects energy
1:    1      a      0.81  -0.32
2:    2      a      0.25  0
3:    3      a      2.05  0
4:    1      b      1.63  -1.66
5:    2      b      2.20  -1.66
6:    3      b      0.49  -1.66
Run Code Online (Sandbox Code Playgroud)

提前致谢

Aru*_*run 2

可能有更好的方法,但这就是我想到的。这就利用了roll=TRUE论证。这个想法是首先设置energy=0.0位置prospects < 0.27

field[prospects < 0.27, energy := 0.0]
Run Code Online (Sandbox Code Playgroud)

然后,如果我们从 中删除 NA 值field,我们可以roll=TRUE通过对所有组合进行连接来使用,如下所示:

field[!is.na(energy)][CJ(c("a", "b"), 1:3), roll=TRUE][, prospects := field$prospects][]
#    player time prospects energy
# 1:      a    1      0.81   0.63
# 2:      a    2      0.25   0.00
# 3:      a    3      2.05   0.00
# 4:      b    1      1.63  -0.28
# 5:      b    2      2.20  -0.28
# 6:      b    3      0.49  -0.28
Run Code Online (Sandbox Code Playgroud)

我们必须重置,prospects因为roll它也会改变。你可以做得更好,但你明白了。


一种变体,以便仅在列上执行滚动energy

field[!is.na(energy)][CJ(c("a", "b"), 1:3), list(energy), 
           roll=TRUE][, prospects := field$prospects][]
Run Code Online (Sandbox Code Playgroud)

na.locf或者从包中使用可能更简单zoo

field[time == 1, energy := round(rnorm(2),2)]
field[prospects < 0.27, energy := 0.0]
require(zoo)
field[, energy := na.locf(energy, na.rm=FALSE)]
Run Code Online (Sandbox Code Playgroud)

如果保证每组的第一行是非 NA 的,则该方法有效,这是通过构造实现的。但如果没有,您也可以按组运行 na.locf :

field[, energy := na.locf(energy, na.rm=FALSE), by=player]
Run Code Online (Sandbox Code Playgroud)

  • 我认为你需要在将 energy 设置为 0 之前检查 energy 是否为 NA,并且如果想要的话可​​以避免使用 `zoo`: `field[prospects &lt; 0.27 &amp; is.na(energy), energy := 0][, energy :=能量[1], by = cumsum(!is.na(energy))][]` (2认同)