有没有办法加快较小的data.frames的子集

时间:2017-04-10 12:24:16

标签: r dataframe data.table subset

我必须经常对data.frame s序列进行子集化(每次运行数百万次)。 data.frame的大小约为200行x 30列。根据状态,data.frame中的值从一次迭代变为下一次迭代。因此,在开头做一个子集是行不通的。

与问题when a data.table starts to be faster than a data.frame相反,我正在寻找加速data.frame / data.table

的给定大小的子集化

以下最低可重现性示例显示,data.frame似乎是最快的:

library(data.table)
nmax <- 1e2 # for 1e7 the results look as expected: data.table is really fast!
set.seed(1)
x<-runif(nmax,min=0,max=10)
y<-runif(nmax,min=0,max=10)
DF<-data.frame(x,y)
DT<-data.table(x,y)

summary(microbenchmark::microbenchmark(
  setkey(DT,x,y),
  times = 10L, unit = "us"))

#               expr    min     lq    mean  median      uq     max neval
# 1 setkey(DT, x, y) 70.326 72.606 105.032 80.3985 126.586 212.877    10

summary(microbenchmark::microbenchmark(
  DF[DF$x>5, ], 
  `[.data.frame`(DT,DT$x < 5,),
  DT[x>5],
  times = 100L, unit = "us"))
#                             expr     min      lq      mean   median       uq     max neval
# 1                 DF[DF$x > 5, ]  41.815  45.426  52.40197  49.9885  57.4010  82.110   100
# 2 `[.data.frame`(DT, DT$x < 5, )  43.716  47.707  58.06979  53.5995  61.2020 147.873   100
# 3                      DT[x > 5] 205.273 214.777 233.09221 222.0000 231.6935 900.164   100

我有什么办法可以改善表现吗?

输入后修改

  • 我正在运行离散事件模拟,对于每个事件,我必须在列表中搜索(我不介意它是data.frame还是data.table)。最有可能的是,我可以实现不同的方法,但后来我必须重新编写超过3年开发的代码。目前,这不是一个选择。但如果没有办法让它变得更快,这将成为未来的选择。
  • 从技术上讲,它不是data.frames的序列,而是一个data.frame的序列,它随每次迭代而变化。但是,这对&#34;如何更快地获得子集没有影响&#34;我希望这个问题现在更加全面。

1 个答案:

答案 0 :(得分:1)

通过转换为矩阵,您将看到性能提升。如果data.frame的全部内容都是数字(或者可以毫不费力地转换),这是一个可行的选择。

我们走了。首先,我修改了数据,使其大小为200x30:

library(data.table)
nmax = 200
cmax = 30
set.seed(1)
x<-runif(nmax,min=0,max=10)
DF = data.frame(x)
for (i in 2:cmax) {
  DF = cbind(DF, runif(nmax,min=0,max=10))
  colnames(DF)[ncol(DF)] = paste0('x',i)
}
DT = data.table(DF)
DM = as.matrix(DF)    # # # or data.matrix(DF) if you have factors

比较,从最快到最慢排列:

summary(microbenchmark::microbenchmark(
  DM[DM[, 'x']>5, ], # # # # Quickest
  as.matrix(DF)[DF$x>5, ], # # # # Still quicker with conversion
  DF[DF$x>5, ], 
  `[.data.frame`(DT,DT$x < 5,),
  DT[x>5],
  times = 100L, unit = "us"))

#                             expr     min       lq      mean   median       uq      max neval
# 1            DM[DM[, "x"] > 5, ]  13.883  19.8700  22.65164  22.4600  24.9100   41.107   100
# 2      as.matrix(DF)[DF$x > 5, ] 141.100 181.9140 196.02329 195.7040 210.2795  304.989   100
# 3                 DF[DF$x > 5, ] 198.846 238.8085 260.07793 255.6265 278.4080  377.982   100
# 4 `[.data.frame`(DT, DT$x < 5, ) 212.342 268.2945 346.87836 289.5885 304.2525 5894.712   100
# 5                      DT[x > 5] 322.695 396.3675 465.19192 428.6370 457.9100 4186.487   100

如果您的用例涉及多次查询数据,那么您只能进行一次转换并将速度提高一个数量级。