我有一个由两个ID变量(一个嵌套在另一个中)和日期索引的数据集,我希望计算此数据中的滚动统计量。
我的真实数据集很大(约200万行),我喜欢使用data.table来提高其他任务的速度...但我无法找到一种最佳使用data.table的方法(即利用二进制搜索并避免矢量扫描)在这个问题。
示例数据:
set.seed(3)
dt1 <-
data.table(id1=c(rep("a",124),rep("b",124)),
id2=c(rep("x",62),rep("y",62)),
date=seq(as.Date("2012-05-01"),as.Date("2012-07-01"),"days"),
var1=rpois(124,14),
var2=rpois(124,3))
setkey(dt1,id1,id2,date)
# create uneven time spacing
dt1 <- dt1[-c(5,10,36,46,58)]
我的最终目标是计算id1 / id2中每一天的“滚动统计”,即:
和(VAR2)/ SUM(VAR1)
包括具有相同id1 / id2组合的所有其他行,并且在该行之前的30天内。
我不确定这是一个很好的第一步,但为了清楚起见,这里是为日期= 2012-06-12获取所有ID所需结果的代码:
dt1[date < as.Date("2012-06-12") & date > as.Date("2012-06-12")-31,
list("newstat"=sum(var1)/sum(var2),
"date"=as.Date("2012-06-12")),by=list(id1,id2)]
id1 id2 newstat date
1: a x 3.925 2012-06-12
2: a y 4.396 2012-06-12
3: b x 3.925 2012-06-12
4: b y 4.396 2012-06-12
我想过尝试在id1和id2上进行笛卡尔自连接,然后将生成的data.table减少到适当的日期范围(我不知道如何在一步中完成)。这给了我想要的结果,但是,我不知道如何在不使用逻辑子集作为减法步骤的i的参数的情况下这样做,这是不可接受的慢。我想我当时没有利用data.table的键,但不知道如何解决这个问题......
示例:
dt1[setkey(dt1[,list(id1,id2,"date_grp"=date)],id1,id2),
list(date_grp,date,var1,var2)][
# Here comes slow subset
date<date_grp & date > date_grp-30,
list("newstat"=sum(var1)/sum(var2)),
by=list(id1,id2,date_grp)]
结果:
id1 id2 date_grp newstat
1: a x 2012-05-02 0.4286
2: a x 2012-05-03 0.4000
3: a x 2012-05-04 0.2857
4: a x 2012-05-06 0.2903
5: a x 2012-05-07 0.3056
---
235: b y 2012-06-27 0.2469
236: b y 2012-06-28 0.2354
237: b y 2012-06-29 0.2323
238: b y 2012-06-30 0.2426
239: b y 2012-07-01 0.2304
答案 0 :(得分:7)
我确信有更好的方法可以做到这一点,但你可以做的一件事是避免完全笛卡尔联接,这就是通过生成带连接键的临时表来杀死你的行为:
dt.dates <- dt1[, list(date.join=seq(as.Date(date - 1, origin="1970-01-01"), by="-1 day", len=30)), by=list(date, id1, id2)]
对于每个date-id组,我们现在已生成允许的加入日期列表。现在我们加入数据并计算我们的指标。
setkey(dt.dates, date.join, id1, id2)
setkey(dt1,date,id1,id2)
dt.dates[dt1][ , sum(var1)/sum(var2), by=list(id1, id2, date)]
我无法复制你的结果6/12,但我认为我们有播种问题。比较:
> dt.date.join[dt1][ , sum(var1)/sum(var2), by=list(id1, id2, date)][date=="2012-06-12"]
id1 id2 date V1
1: a x 2012-06-12 3.630631
2: a y 2012-06-12 4.434783
3: b x 2012-06-12 3.634783
4: b y 2012-06-12 4.434783
> dt1[date < as.Date("2012-06-12") & date > as.Date("2012-06-12")-31, list("newstat"=sum(var1)/sum(var2), "date"=as.Date("2012-06-12")),by=list(id1,id2)]
id1 id2 newstat date
1: a x 3.630631 2012-06-12
2: a y 4.434783 2012-06-12
3: b x 3.634783 2012-06-12
4: b y 4.434783 2012-06-12
基本上是相同的结果。