以缺失数据为条件的滚动累积和
rolling cumulative sums conditional on missing data
我想按 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 个时间段的滚动 window,我需要以下输出:
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
之前,我想我们需要根据 'time' 变量创建另一个分组变量 ('indx')。我发现对于项目 'B',时间不连续,即。 2 不见了。所以,我们可以使用 diff
来创建一个基于相邻元素差异的逻辑索引。如果差异不是 1,它将 return TRUE 否则为 FALSE。由于 diff
输出比列的 length
少 length
1,我们可以用 TRUE
填充,然后执行 cumsum
来创建 'indx'变量。
library(zoo)
DT[, indx:=cumsum(c(TRUE, diff(time)!=1))]
第二步,我们同时使用'indx'和'time'作为分组变量,用k=2
得到'sales'的rollsum
,也根据条件,如果组中的元素数大于1我们只需要这样做(if(.N >1)
),否则应该return '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 的建议,我们可以使用 library(RcppRoll)
中的 roll_sum
可以更有效地使用,因为它甚至可以处理少于 'k' 的行数。这样,我们就可以去掉我之前方案中的if/else
条件了。 (完全归功于@Khashaa)
library(RcppRoll)
DT[, sales_rolling2 := c(sales[1L], roll_sum(sales, 2)), by = .(indx, item)]
我想按 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 个时间段的滚动 window,我需要以下输出:
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
之前,我想我们需要根据 'time' 变量创建另一个分组变量 ('indx')。我发现对于项目 'B',时间不连续,即。 2 不见了。所以,我们可以使用 diff
来创建一个基于相邻元素差异的逻辑索引。如果差异不是 1,它将 return TRUE 否则为 FALSE。由于 diff
输出比列的 length
少 length
1,我们可以用 TRUE
填充,然后执行 cumsum
来创建 'indx'变量。
library(zoo)
DT[, indx:=cumsum(c(TRUE, diff(time)!=1))]
第二步,我们同时使用'indx'和'time'作为分组变量,用k=2
得到'sales'的rollsum
,也根据条件,如果组中的元素数大于1我们只需要这样做(if(.N >1)
),否则应该return '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 的建议,我们可以使用 library(RcppRoll)
中的 roll_sum
可以更有效地使用,因为它甚至可以处理少于 'k' 的行数。这样,我们就可以去掉我之前方案中的if/else
条件了。 (完全归功于@Khashaa)
library(RcppRoll)
DT[, sales_rolling2 := c(sales[1L], roll_sum(sales, 2)), by = .(indx, item)]