鉴于data.table
,我想快速将中的项目进行子集。例如:
dt = data.table(a=1:10, key="a")
dt[a > 3 & a <= 7]
这仍然很慢。我知道我可以做连接来获取单独的行,但是有没有办法确定data.table
被排序以获得这种类型的快速子集?
这就是我正在做的事情:
dt1 = data.table(id = 1, ym = c(199001, 199006, 199009, 199012), last_ym = c(NA, 199001, 199006, 199009), v = 1:4, key=c("id", "ym"))
dt2 = data.table(id = 1, ym = c(199001, 199002, 199003, 199004, 199005, 199006, 199007, 199008, 199009, 199010, 199011, 199012), v2 = 1:12, key=c("id","ym"))
对于每个id
,此处只有ym
,dt1
,我想在当前v2
之间将ym
的值相加在dt1
和ym
中的最后dt1
。也就是说,对于ym == 199006
中的dt1
,我想返回list(v2 = 2 + 3 + 4 + 5 + 6)
。这些是v2
中dt2
的值等于或小于当前ym
(不包括前一个ym)。在代码中:
expr = expression({ #browser();
cur_id = id;
cur_ym = ym;
cur_dtb = dt2[J(cur_id)][ym <= cur_ym & ym > last_ym];
setkey(cur_dtb , ym);
list(r = sum(cur_dtb$v2))
})
dt1[,eval(expr ),by=list(id, ym)]
答案 0 :(得分:4)
要避免逻辑条件,请执行dt1
和dt2
的滚动连接。然后将ym
向前移动id
内的一个位置。最后,按v2
和id
加总ym
:
setkey(dt1, id, last_ym)
setkey(dt2, id, ym)
dt1[dt2,, roll = TRUE][
, list(v2 = v2, ym = c(last_ym[1], head(ym, -1))), by = id][
, list(v2 = sum(v2)), by = list(id, ym)]
请注意,我们希望对last_ym
以后的所有内容求和,因此dt1
上的键必须为last_ym
而不是ym
。
结果是:
id ym v2
1: 1 199001 1
2: 1 199006 20
3: 1 199009 24
4: 1 199012 33
更新:更正
答案 1 :(得分:1)
无论data.table
是如何排序的,您都将被限制在首先评估a > 3 & a <= 7
所需的时间:
> dt = data.table(a=1:10000000, key="a")
> system.time(dt$a > 3 & dt$a <= 7)
user system elapsed
0.18 0.01 0.20
> system.time(dt[,a > 3 & a <= 7])
user system elapsed
0.18 0.05 0.24
> system.time(dt[a > 3 & a <= 7])
user system elapsed
0.25 0.07 0.31
替代方法:
> system.time({Indices = dt$a > 3 & dt$a <= 7 ; dt[Indices]})
user system elapsed
0.28 0.03 0.31
多个子集
如果您在临时基础上分解因素而不是一次性完成所有因素,那么这里可能存在速度问题:
> dt <- data.table(A=sample(letters, 10000, replace=T))
> system.time(for(i in unique(dt$A)) dt[A==i])
user system elapsed
5.16 0.42 5.59
> system.time(dt[,.SD,by=A])
user system elapsed
0.32 0.03 0.36