Data.table 的滚动子集用于滚动统计

Rolling Subsetting of Data.table for rolling statistics

我有一个奇怪的问题,我知道我可以用 apply 或其他一些循环结构来解决,但我觉得应该有一个非常聪明的方法来做到这一点。我有一个 data.table example_dt,我从中提取 2 个 id 列以形成一个名为 id_dt.

的 id data.table

然后我想使用这些 id 索引到 example_dt 来计算一些统计数据。诀窍在于第一个 ID id1 需要匹配。第二个id,id2,只要在一定范围内即可。我重命名了 id_dt 中的列以避免命名冲突。我不完全确定 data.table

中的范围界定是怎么回事
library(data.table)
example_dt <- data.table( id1 = c(rep('a', 7), rep('b', 7)), id2 = c(1:7, 1:7), x1 = c(rep(1:2,7)))
id_dt <- example_dt[,.(id1, id2)]
setnames(id_dt, names(id_dt), c('id1_idx','id2_idx') )
result_dt <- id_dt[,example_dt[id1 == id1_idx & id2 <= id2_idx & id2 >= id2_idx - 2, mean(x1)]]

我得到的只是一个值 1.5

> result_dt
[1] 1.5

我要的是这个:

id1 id2 x1  mean
a   1   1   1
a   2   2   1.5
a   3   1   1.333333333
a   4   2   1.666666667
a   5   1   1.333333333
a   6   2   1.666666667
a   7   1   1.333333333
b   1   2   2
b   2   1   1.5
b   3   2   1.666666667
b   4   1   1.333333333
b   5   2   1.666666667
b   6   1   1.333333333
b   7   2   1.666666667

就像我说的,我知道我可以用 apply 或其他一些循环结构来做到这一点。我想看看有没有什么我不知道的聪明的data.table咒语。

这是使用 rolling joins 的一种方法:

setkey(example_dt, id1, id2)
idx1 = example_dt[.(id1, id2-2), roll=-Inf, which=TRUE]
idx2 = example_dt[.(id1, id2), roll=Inf, which=TRUE]

mapply(function(x,y) mean(example_dt$x1[x:y]), idx1, idx2)
#  [1] 1.000000 1.500000 1.333333 1.666667 1.333333 1.666667 1.333333 2.000000 1.500000
# [10] 1.666667 1.333333 1.666667 1.333333 1.666667

也可以使用 foverlaps() 来完成,但似乎有点矫枉过正。我建议您查看 ?data.table 中的 roll 参数,如果您无法掌握该参数,请在此处练习示例。(直到完成连接的小插曲)。对于其他小插图,请检查 Getting started page. For vignettes planned, have a look at this post.

这已经出现了很多次,可能值得在 data.table 中使 between() 函数能够(有效地)执行此操作。我认为项目页面上某处有一个 FR。

至于为什么你得到一个值,你正在做 DT[rows, mean(col)],它读取.. 为 rows 中指定的行提取 col,并计算其平均值。那应该 return 一个单一的值。