使用Rcpp可以提高速度吗
最近,我在Rcpp软件包上遇到了麻烦,看到了它在速度方面的巨大改进,尤其是在循环方面。我正在编写一个模拟程序,不断在5D阵列上执行矩阵代数。一个例子如下所示:使用Rcpp可以提高速度吗,r,rcpp,R,Rcpp,最近,我在Rcpp软件包上遇到了麻烦,看到了它在速度方面的巨大改进,尤其是在循环方面。我正在编写一个模拟程序,不断在5D阵列上执行矩阵代数。一个例子如下所示: library(rbenchmark) Mat<- assign("Mat",array(10,c(10,10,9,4,9))) Mat2<-matrix(c(runif(16,0,1)),nrow=4,ncol=4) FuncR<-function(x){ for(i in 1:dim(Mat)[1]){
library(rbenchmark)
Mat<- assign("Mat",array(10,c(10,10,9,4,9)))
Mat2<-matrix(c(runif(16,0,1)),nrow=4,ncol=4)
FuncR<-function(x){
for(i in 1:dim(Mat)[1]){
for(j in 1:dim(Mat)[2]){
for(loc in 1:dim(Mat)[3]){
for(Yr in 1:dim(Mat)[5]){
Mat[i,j,loc,,Yr]<<-floor(x%*%Mat[i,j,loc,,Yr])
}
}
}
}
}
benchmark(FuncR(Mat2))
test replications elapsed relative user.self sys.self user.child sys.child
1 FuncR(Mat2) 100 17.008
1 7.228 0.016 0 0
库(rbenchmark)
Mat我觉得在5D空间中处理数据帧比处理切片舒服得多,所以下面是我解决这个问题的方法:
library(dplyr)
melt(Mat) %>%
setNames(c('i','j','loc','k','Yr','value')) %>%
group_by(i,j,loc,Yr) %>%
mutate(out=floor(Mat2 %*% value))
当然,也可以使用data.table
获得类似的解决方案。dplyr
和data.table
解决方案预计比您的代码更快。我觉得在5D空间中处理数据帧比处理切片舒服得多,因此以下是我解决此问题的方法:
library(dplyr)
melt(Mat) %>%
setNames(c('i','j','loc','k','Yr','value')) %>%
group_by(i,j,loc,Yr) %>%
mutate(out=floor(Mat2 %*% value))
当然,也可以使用data.table
获得类似的解决方案。dplyr
和data.table
解决方案预计会比您的代码更快。只需更直接地使用矩阵乘法,您就可以获得与Rcpp类似的性能
使用aperm
将第四个维度放到前面,然后展平到两个维度。您可以执行一个%*%
,然后反转该过程
> Mat3 <- aperm(Mat, c(4,1,2,3,5))
> dim(Mat3)
[1] 4 10 10 9 9
> dim(Mat3) <- c(4,prod(10,10,9,9))
> Mat4 <- Mat2 %*% Mat3
> dim(Mat4)
[1] 4 8100
> dim(Mat4) <- c(4,10,10,9,9)
> Mat5 <- aperm(Mat4, c(2,3,4,1,5))
LGTM
我在“学术”代码中看到过很多这种模式,在行业中则不多见。由于乘法运算已经不存在了,所以它确实用一些内存来弥补代码的不足
如果您对代码库的其他部分有控制,您可以考虑更改<代码> Mat < /Cord>对象的内存布局,然后<>代码> Apple < /C> >不一定需要
< P>。p>
使用aperm
将第四个维度放到前面,然后展平到两个维度。您可以执行一个%*%
,然后反转该过程
> Mat3 <- aperm(Mat, c(4,1,2,3,5))
> dim(Mat3)
[1] 4 10 10 9 9
> dim(Mat3) <- c(4,prod(10,10,9,9))
> Mat4 <- Mat2 %*% Mat3
> dim(Mat4)
[1] 4 8100
> dim(Mat4) <- c(4,10,10,9,9)
> Mat5 <- aperm(Mat4, c(2,3,4,1,5))
LGTM
我在“学术”代码中看到过很多这种模式,在行业中则不多见。由于乘法运算已经不存在了,所以它确实用一些内存来弥补代码的不足
如果您对代码库的其他部分有控制,您可以考虑更改<代码> Mat < /Cord>对象的内存布局,然后<代码> Apple < /C> >将不需要
< P>可选地,您可以考虑<代码>张量库:
> require(tensor)
> MT <- tensor(Mat2, Mat, 2, 4)
> dim(MT)
[1] 4 10 10 9 9
> MT[,1,1,1,1]
[1] 6.357168721 18.288843057 21.215756948 10.310288982
>需要(张量)
>MT dim(MT)
[1] 4 10 10 9 9
>MT[,1,1,1,1]
[1] 6.357168721 18.288843057 21.215756948 10.310288982
< /代码> 可选地,您可以考虑<代码>张量< /C>库:
> require(tensor)
> MT <- tensor(Mat2, Mat, 2, 4)
> dim(MT)
[1] 4 10 10 9 9
> MT[,1,1,1,1]
[1] 6.357168721 18.288843057 21.215756948 10.310288982
>需要(张量)
>MT dim(MT)
[1] 4 10 10 9 9
>MT[,1,1,1,1]
[1] 6.357168721 18.288843057 21.215756948 10.310288982
代码现在的样子——它肯定会从使用Rcpp中受益;我的感觉是,您将获得至少一个数量级的运行时提升。然而,我认为在R中也可能有一种有效的方法,例如,以长格式展开Mat
,并使用数据。table
为什么这行中有assign
<代码>Mat比较(有点普遍),包括Rcpp。代码现在的样子——它肯定会从使用Rcpp中受益;我的感觉是,您将获得至少一个数量级的运行时提升。然而,我认为在R中也可能有一种有效的方法,例如,以长格式展开Mat
,并使用数据。table
为什么这行中有assign
<代码>已比较的材料(有点普遍),包括Rcpp。