提高 data.table 子集性能

Improving data.table subsetting performance

我是 运行 大型蒙特卡洛模拟,我发现 sub-setting/searching 我的数据是我代码中最慢的部分。为了测试一些替代方案,我使用数据帧、data.table 和矩阵对性能进行了基准测试。 这是基准代码:

library(data.table)
#install.packages('profvis')
library(profvis)
x.df = data.frame(a=sample(1:10,10000,replace=T), b=sample(1:10,10000,replace=T)) # set up a dataframe
x.dt = as.data.table(x.df) # a data.table
setkey(x.dt,a) # set key for faster searches
x.mat = as.matrix(x.df) # a matrix

profvis({
for (i in 1:10000) {
  # test simple subsetting
  xsubset.mat = x.mat[100:200,2]
  xsubset.df = x.df[100:200,2]
  xsubset.dt = x.dt[100:200,2]
  # test search preformance
  xsearch.mat = x.mat[which(x.df$a==10),2]
  xsearch.df = x.df[which(x.df$a==10),2]
  xsearch.dt = x.dt[.(10),2]
}
})

这是我的结果: 说真的,我喜欢 data.table 的紧凑语法,我想知道是否可以做些什么来提高它的性能。根据创作者的说法,它应该超级快。我是不是用错了?

经过更多基准测试后,我现在明白了这个问题。最快的程序包取决于我是在进行多次小搜索还是进行一次大搜索。 data.table 似乎每次搜索都有很多开销,使其更适合处理一个巨大的 table,而不是很多小的搜索。

考虑以下代码,并与原始代码进行比较:

# make a giant table, but search it only once:
x.df = data.frame(a=sample(1:10,100000000,replace=T), b=sample(1:10,100000000,replace=T))
x.dt = as.data.table(x.df)
setkey(x.dt,a)
x.mat = as.matrix(x.df)

profvis({
for (i in 1:1) {
  xsubset.mat = x.mat[100:200,2]
  xsubset.df = x.df[100:200,2]
  xsubset.dt = x.dt[100:200,2]

  xsearch.mat = x.mat[which(x.df$a==10),2]
  xsearch.df = x.df[which(x.df$a==10),2]
  xsearch.dt = x.dt[.(10),2]
}
})

结果: