按上一行和实际行定义值

时间:2019-01-21 21:02:32

标签: r data.table locf

我有一个data.table,其中有两个字段,startvalueendValue,我需要根据上一行和实际行中的一些信息进行填充。尽管这在某种程度上类似于thisthis,但我无法获得想要的结果。

虚拟数据:

a <- data.table(user = c("A", "A", "A", "B", "B"), 
                gap = c(1, 0, 2, 2, 3), 
                priority = c(1, 3, 2, 2, 1))

然后我将startValue的所有优先级固定为== 1:

setkey(a, user, priority)
a[priority == 1, startValue := 0]

,然后将endValue设置为startValue

a[!is.na(startValue), endValue := startValue + gap*3]

现在是问题所在。我希望第2行(用户A,优先级2)中的startValue与第1行的endValue相同,因此我可以计算出新的endValue。我知道,我可以使用循环,但是我想知道是否可以通过使用任何其他函数或函数组合来做到这一点。

我尝试了shiftzoo:na.locf的几种组合,但是总是弄乱了已经存在的值。

预期结果:

b <- structure(list(user = c("A", "A", "A", "B", "B"), 
                    gap = c(1, 2, 0, 3, 2), 
                    priority = c(1, 2, 3, 1, 2), 
                    startValue = c(0, 3, 9, 0, 9), 
                    endValue = c(3, 9, 9, 9, 15)), 
               row.names = c(NA, -5L), 
               class = c("data.table", "data.frame"))

2 个答案:

答案 0 :(得分:2)

我们可以使用accumulate中的purrr

library(purrr)
library(data.table)
a[, endValue := accumulate(gap,  ~   .x + .y * 3, .init = 0)[-1], user
   ][, startValue := shift(endValue, fill = 0), user][]
all.equal(a, b, check.attributes = FALSE)
#[1] TRUE

或者使用Reduce中的base R创建“ endValue”列,然后使用“ endValue”的lag创建按“用户”分组的“ startValue”

a[, endValue := Reduce(function(x, y) x + y *3, gap, 
     accumulate = TRUE, init = 0)[-1], user]

答案 1 :(得分:1)

首先,使用cumsum计算最终值。然后使用shift获取初始值。

a[ , c("startValue", "endValue") := {
  e1 <- startValue[1] + gap[1] * 3
  endValue <- c(e1, e1 + cumsum(gap[-1] * 3))
  startValue <- shift(endValue, fill = startValue[1])
  .(startValue, endValue)
}, by = user]

#    user gap priority startValue endValue
# 1:    A   1        1          0        3
# 2:    A   2        2          3        9
# 3:    A   0        3          9        9
# 4:    B   3        1          0        9
# 5:    B   2        2          9       15