我想在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)
对于2个时间段的滚动窗口,我想要以下输出:
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行的结果只包括最新的观察结果。
答案 0 :(得分:3)
我们可以使用rollsum
中的library(zoo)
来计算滚动金额。在应用rollsum
之前,我想我们需要根据'time'变量创建另一个分组变量('indx')。我发现对于项目'B',时间不是连续的,即。 2缺少。因此,我们可以使用diff
根据相邻元素的差异创建逻辑索引。如果差异不是1,则返回TRUE或FALSE。由于diff
输出比列length
少length
1,我们可以使用TRUE
填充,然后执行cumsum
创建' indx'变量。
library(zoo)
DT[, indx:=cumsum(c(TRUE, diff(time)!=1))]
在第二步中,我们同时使用'indx'和'time'作为分组变量,使用rollsum
获取'sales'的k=2
,并且还基于条件,如果数字组中的元素大于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
的{{1}}可以更有效地使用,因为它甚至可以使用小于'k'的行数。通过这种方式,我们可以删除先前解决方案中的library(RcppRoll)
条件。 (完全归功于@Khashaa)
if/else