【问题标题】:fast subsetting in data.table in RR中data.table中的快速子集
【发布时间】:2013-07-03 21:41:09
【问题描述】:

给定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,这里只有1个,而dt1中的ym,我想在dt1中的当前ym和最后一个ym之间求和v2的值在dt1。也就是说,对于dt1 中的ym == 199006,我想返回list(v2 = 2 + 3 + 4 + 5 + 6)。这些是dt2v2 的值等于或小于当前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)]

【问题讨论】:

  • 我看不出这有多慢?在 1000 万行的 data.table 上使用 system.time 花费了 0.28 秒。
  • 是的,但如果你必须这样做 100,000 次,那太慢了!我可能不得不为我正在做的事情想出一个不同的算法。
  • 你在使用for循环吗?
  • 不,我不是。让我举个例子。
  • 您的示例根本不适合我。 ://

标签: r join data.table subset


【解决方案1】:

为避免逻辑条件,请执行dt1dt2 的滚动连接。然后在id 内将ym 向前移动一位。最后,将v2idym 相加:

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

更新:更正

【讨论】:

  • 抱歉,我对所有 setkey 表达式有点困惑……那些看起来不正确……?
  • 我已将它们修复为与我实际使用的内容相对应,并添加了一些解释。
【解决方案2】:

不管data.table 是否已排序,您首先将受限于评估a &gt; 3 &amp; a &lt;= 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

【讨论】:

  • 刚刚发布了一个例子,也许你可以想到一个更好的方法来做到这一点
猜你喜欢
  • 1970-01-01
  • 2018-02-11
  • 2012-12-08
  • 2013-01-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多