静态大小的Rcpp空列表会比list.push_back()更有效吗



如果希望迭代一个函数并将结果添加到Rcpp中的列表中,可以使用.push_back()方法,例如:

List appended_list() {
List emptylist = List::create();
for (int i = 0; i < 3; i++) {
emptylist.push_back(i);
}
return emptylist;
}

然而,我说列表每次都会被重新定义,因此这种方法效率很低,这是正确的吗?有没有办法创建一个静态大小的列表(即创建一个n元素的列表,其中每个元素都是NULLNA或类似的元素(?例如,要在R中做到这一点,可以写:

emptylist <- list()
length(emptylist) <- 3
for (i in 1:3) {
emptylist[[i]] <- i
}

有办法在Rcpp中做到这一点吗?它会更有效率吗?

预先分配的列表将更快。如果您不确定如何创建预先确定大小的列表,我的建议是,你可能需要花一些时间介绍Rcpp材料。一些好的资源是:

  • Rcpp提供的小插曲,特别是简介和常见问题小插曲。除了从R访问它们之外,你还可以在网上找到它们
  • 每个人的Rcpp
  • 哈德利关于Rcpp的章节

以下是一个示例,显示了避免push_back()的速度有多快。在so.cpp中,我们有

#include <Rcpp.h>
// [[Rcpp::export]]
void test1() {
Rcpp::List out;
for ( int i = 0; i < 1000; ++i ) {
out.push_back(i);
}
}
// [[Rcpp::export]]
void test2() {
Rcpp::List out(1000);
for ( int i = 0; i < 1000; ++i ) {
out[i] = i;
}
}

然后我们将这些功能相互比较:

Rcpp::sourceCpp("so.cpp")
library(microbenchmark)
microbenchmark(empty_list = test1(), pre_allocated = test2())
Unit: microseconds
expr      min       lq       mean    median        uq      max
empty_list 3553.549 3755.405 4337.71591 3894.3075 4106.7500 8790.787
pre_allocated   22.089   23.689   38.67364   24.6645   26.1165 1339.443
neval
100
100

所以你可以看到这里有很大的不同。当然,在这个简化的情况下;相当大的";这种差异对人类来说是不明显的,但在更复杂的用例中,或者在多次调用这样一个函数的情况下,它实际上可能是";相当可观">

通常情况下,总是希望进行预分配。

是的,你重新发现了一些我们记录了近十年的东西("push_back在RSEXP类型上很贵"(。如果您事先不知道自己的大小,请使用STL中的标准容器(在生长时具有更好的行为(,并在最后进行转换。

最新更新