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