I would like to update the value in a table with values of the previous row, within groups, (and probably stop the updates on a given condition)
Here is an example:
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
Here is the table I have.
> 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
Here is the table I want.
> 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
Thanks in advance
Probably there are better ways, but this is what came to my mind. This makes use of roll=TRUE
argument. The idea is to first set energy=0.0
where prospects < 0.27
:
field[prospects < 0.27, energy := 0.0]
Then, if we remove the NA values from field
, we can use roll=TRUE
by doing a join with all combinations as follows:
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
We've to reset prospects
because the roll
changes it too. You could do it better, but you get the idea.
A variation, so that the roll is performed only on energy
column:
field[!is.na(energy)][CJ(c("a", "b"), 1:3), list(energy),
roll=TRUE][, prospects := field$prospects][]
Or it may be simpler to use na.locf
from package 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)]
which works if the first row of each group is guaranteed to be non-NA, which it is here by construction. But if not, you can run na.locf by group, too :
field[, energy := na.locf(energy, na.rm=FALSE), by=player]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With