我想计算data.table中每个项目的滚动累积和。有时,在给定的时间段内数据丢失。
set.seed(8)
item <- c(rep("A",4), rep("B",3))
time <- c(1,2,3,4,1,3,4)
sales <- rpois(7,5)
DT <- data.table(item, time,sales)
对于两个时间段的滚动窗口,我想要以下输出:
item time sales sales_rolling2
1: A 1 5 5
2: A 2 3 8
3: A 3 7 10
4: A 4 6 13
5: B 1 4 4
6: B 3 6 6
7: B 4 4 10
注意,项目B在时刻2没有数据。因此,第6行的结果只包含最新的观测值。
我们可以用library(zoo)
中的rollsum
来做滚动和。在应用rollsum
之前,我想我们需要基于"时间"变量创建另一个分组变量("索引")。我发现对于B项,时间是不连续的。2不见了。因此,我们可以使用diff
根据相邻元素的差异创建一个逻辑索引。如果差值不为1,则返回TRUE或FALSE。由于length
1的diff
输出小于列的length
,我们可以填充TRUE
,然后执行cumsum
来创建'indx'变量。
library(zoo)
DT[, indx:=cumsum(c(TRUE, diff(time)!=1))]
在第二步中,我们使用'indx'和'time'作为分组变量,使用k=2
获得'sales'的rollsum
,并且还基于这样的条件,即如果组中的元素数量大于1,我们只需要这样做(if(.N >1)
),否则它应该返回'sales',创建'sales_rolling2',并将'indx'分配(:=
)为NULL,因为在预期输出中不需要它。
DT[, sales_rolling2 := if(.N>1) c(sales[1],rollsum(sales,2)) else sales,
by = .(indx, item)][,indx:= NULL]
# item time sales sales_rolling2
#1: A 1 5 5
#2: A 2 3 8
#3: A 3 7 10
#4: A 4 6 13
#5: B 1 4 4
#6: B 3 6 6
#7: B 4 4 10
更新根据@Khashaa的建议,我们可以使用roll_sum
从library(RcppRoll)
可以更有效地使用,因为它甚至可以在行数小于"k"的情况下工作。这样,我们就可以在我之前的解决方案中删除if/else
条件。(全部归功于@Khashaa)
library(RcppRoll)
DT[, sales_rolling2 := c(sales[1L], roll_sum(sales, 2)), by = .(indx, item)]