Rcpp-使用较大的列表加速嵌套列表操作
Rcpp列表操作Rcpp-使用较大的列表加速嵌套列表操作,r,rcpp,R,Rcpp,Rcpp列表操作 // [[Rcpp::export]] vec cf_shallowstrict_i(const Rcpp::List & inlist){ NumericVector ave = inlist["a"]; NumericMatrix bma = inlist["b"]; arma::vec avec(ave.begin(), ave.size(), false, true); arma::mat bmat(bma.begin(), bma.rows
// [[Rcpp::export]]
vec cf_shallowstrict_i(const Rcpp::List & inlist){
NumericVector ave = inlist["a"];
NumericMatrix bma = inlist["b"];
arma::vec avec(ave.begin(), ave.size(), false, true);
arma::mat bmat(bma.begin(), bma.rows(), bma.cols(), false, true);
return( vectorise(trans(trans(avec) * bmat)));
}
// [[Rcpp::export]]
mat cf_shallowstrict(const Rcpp::List & outerlist){
int outerlistsize =outerlist.size();
mat outmatrix(outerlistsize,4);
for(int ll=0; ll<outerlistsize; ll++){
Rcpp::List innerlist = outerlist[ll];
outmatrix.row(ll)= trans(cf_shallowstrict_i(innerlist));
}
return(outmatrix);
}
注:这篇文章是根据最初的反馈进行编辑的
Rcpp和列表操作-这是这里的热门话题。当对象较大时,列表中对象的复制与浅复制确实很重要。下面我用一个简单的例子来说明这一点
问题
有没有其他加快访问嵌套循环元素的方法
设置
首先,让我介绍一下数据结构:嵌套列表,其中内部列表包含一个向量和一个矩阵。一个嵌套列表将填充包含小向量/矩阵的列表,另一个填充大向量/矩阵的列表。这种结构与许多层次模型是一致的,在层次模型中,对每个i在i级进行某种计算
R
假设我们想对这些列表中的每一个做一个简单的矩阵乘法。一个简单的R版本:
rfun=function(outerlist){
outerlistsize=length(outerlist)
outmatrix=matrix(NA,outerlistsize,4)
for(ll in 1:outerlistsize){
outmatrix[ll,]= outerlist[[ll]]$a %*% outerlist[[ll]]$b
}
}
Rcpp
现在让我们在Rcpp中执行此操作。不同版本:
- 香草犰狳(复制对象)
- 浅拷贝犰狳
- 具有浅拷贝和固定尺寸的犰狳
- 香草结构
- 具有初始浅复制的结构(但最终结构创建会复制对象)
#include <RcppArmadillo.h>
using namespace Rcpp;
using namespace arma;
// [[Rcpp::depends("RcppArmadillo")]]
// [[Rcpp::export]]
vec cf_copy_i(Rcpp::List inlist){
vec avec = Rcpp::as<arma::vec>(inlist["a"]);
mat bmat = Rcpp::as<arma::mat>(inlist["b"]);
return( vectorise(trans(trans(avec) * bmat)));
}
// [[Rcpp::export]]
mat cf_copy(Rcpp::List outerlist){
int outerlistsize =outerlist.size();
mat outmatrix(outerlistsize,4);
for(int ll=0; ll<outerlistsize; ll++){
Rcpp::List innerlist = outerlist[ll];
outmatrix.row(ll)= trans(cf_copy_i(innerlist));
}
return(outmatrix);
}
。。。和大数据
## test replications elapsed relative
## 3 cf_shallow(bgd) 100 3.47 1.000
## 4 cf_shallowstrict(bgd) 100 3.54 1.020
## 1 rfun(bgd) 100 11.28 3.251
## 2 cf_copy(bgd) 100 17.52 5.049
## 6 cf_structshallow(bgd) 100 51.51 14.844
## 5 cf_struct(bgd) 100 64.82 18.680
“但是当里面的对象更大时,Rcpp实际上会使事情变慢”——乍一看,这可能是因为您转换为
arma::
类型。当您从Rcpp类型转换为,例如,arma::vec
,arma::mat
等时,必须执行深度复制,对于较大的对象,这可能需要相当长的时间。您是否仅使用Rcpp类型测试了您的声明?请注意,有一些方法可以实例化arma对象,而无需复制,这就是我们在接口上所做的。但是@nrussell是正确的,这是你要尝试的第一件事。一旦你做到了这一点,尝试零成本arma转换。听起来似乎有道理。这个简单的例子在普通的Rcpp中很容易实现,而其他得益于Armadillo易用性的代码片段则不然。德克:有关于零成本arma转换的指导吗?看看arma文档中的高级构造函数;有两个布尔开关承诺不改变dims,并重用内存。谢谢!这确实加快了速度。不过,strict=true参数似乎没有影响。有什么评论吗?
// [[Rcpp::export]]
vec cf_shallowstrict_i(const Rcpp::List & inlist){
NumericVector ave = inlist["a"];
NumericMatrix bma = inlist["b"];
arma::vec avec(ave.begin(), ave.size(), false, true);
arma::mat bmat(bma.begin(), bma.rows(), bma.cols(), false, true);
return( vectorise(trans(trans(avec) * bmat)));
}
// [[Rcpp::export]]
mat cf_shallowstrict(const Rcpp::List & outerlist){
int outerlistsize =outerlist.size();
mat outmatrix(outerlistsize,4);
for(int ll=0; ll<outerlistsize; ll++){
Rcpp::List innerlist = outerlist[ll];
outmatrix.row(ll)= trans(cf_shallowstrict_i(innerlist));
}
return(outmatrix);
}
// [[Rcpp::export]]
vec cf_nolist_i(const vec & avec, const mat & bmat){
vec outvec= vectorise(trans(trans(avec) * bmat));
return(outvec);
}
struct stuff{
vec a;
mat b;
};
// [[Rcpp::export]]
mat cf_struct(const Rcpp::List & outerlist){
int outerlistsize =outerlist.size();
std::vector<stuff> list_vector;
stuff listi_struct;
List listi;
for(int ij=0; ij<outerlistsize; ij++){
listi = outerlist[ij];
listi_struct.a = as<vec>(listi["a"]);
listi_struct.b = as<mat>(listi["b"]);
list_vector.push_back(listi_struct);
}
mat outmatrix(outerlistsize,4);
for(int ll=0; ll<outerlistsize; ll++){
outmatrix.row(ll)= trans(cf_nolist_i(list_vector[ll].a, list_vector[ll].b));
}
return(outmatrix);
}
// [[Rcpp::export]]
mat cf_structshallow(const Rcpp::List & outerlist){
int outerlistsize =outerlist.size();
std::vector<stuff> list_vector;
stuff listi_struct;
List listi;
for(int ij=0; ij<outerlistsize; ij++){
listi = outerlist[ij];
NumericVector ave = listi["a"];
NumericMatrix bma = listi["b"];
arma::vec avec(ave.begin(), ave.size(), false, true);
arma::mat bmat(bma.begin(), bma.rows(), bma.cols(), false, true);
listi_struct.a = avec;
listi_struct.b = bmat;
list_vector.push_back(listi_struct);
}
mat outmatrix(outerlistsize,4);
for(int ll=0; ll<outerlistsize; ll++){
outmatrix.row(ll)= trans(cf_nolist_i(list_vector[ll].a, list_vector[ll].b));
}
return(outmatrix);
}
library(rbenchmark)
smd=outerlist_smalldata
bgd=outerlist_bigdata
bench_small=benchmark(rfun(smd),cf_copy(smd),cf_shallow(smd),cf_shallowstrict(smd),cf_struct(smd),cf_structshallow(smd), order="relative")
print(bench_small[,1:4])
## test replications elapsed relative
## 3 cf_shallow(smd) 100 0.03 1.000
## 4 cf_shallowstrict(smd) 100 0.03 1.000
## 2 cf_copy(smd) 100 0.08 2.667
## 1 rfun(smd) 100 0.14 4.667
## 6 cf_structshallow(smd) 100 0.39 13.000
## 5 cf_struct(smd) 100 0.40 13.333
## test replications elapsed relative
## 3 cf_shallow(bgd) 100 3.47 1.000
## 4 cf_shallowstrict(bgd) 100 3.54 1.020
## 1 rfun(bgd) 100 11.28 3.251
## 2 cf_copy(bgd) 100 17.52 5.049
## 6 cf_structshallow(bgd) 100 51.51 14.844
## 5 cf_struct(bgd) 100 64.82 18.680