我不确定如何将您的循环转换为矢量化操作。但是,有两个相当简单的选项可以大幅提高性能。第一种是简单地将你的循环放入一个R
函数中,并使用compiler
包来预编译它。第二个稍微复杂的选项是将R
循环转换为c++
循环并使用Rcpp
包将其链接到R
函数。然后你调用一个R
函数将它传递给c++
快速的代码。我展示了这些选项和时间。我非常感谢来自 Rcpp listserv 的 Alexandre Bujard 的帮助,他帮助我解决了我不理解的指针问题。
首先,这是你的R
循环作为一个函数,foo.r
.
## Your R loop as a function
foo.r <- function(d) {
ans <- d
running_total <- 100
count <- 1
max <- 100
toggle <- FALSE
processing <- FALSE
for(i in d){
if(i != 0 ){
processing <- TRUE
if(toggle == TRUE){
ans[count] <- 0
} else {
running_total = running_total + i;
if (running_total > max) {
max <- running_total
} else if (0.98*max > running_total) {
toggle <- TRUE
}
}
}
if(i == 0 && processing == TRUE) {
running_total <- 100
max <- 100
toggle <- FALSE
}
count <- count + 1
}
return(ans)
}
现在我们可以加载compiler
包并编译函数并调用它foo.rcomp
。
## load compiler package and compile your R loop
require(compiler)
foo.rcomp <- cmpfun(foo.r)
这就是编译路径所需的全部内容。这一切都R
非常容易。现在对于c++
方法,我们使用Rcpp
包以及inline
允许我们“内联”c++
代码的包。也就是说,我们不必制作源文件并编译它,我们只需将它包含在R
代码中,编译就会为我们处理。
## load Rcpp package and inline for ease of linking
require(Rcpp)
require(inline)
## Rcpp version
src <- '
const NumericVector xx(x);
int n = xx.size();
NumericVector res = clone(xx);
int toggle = 0;
int processing = 0;
int tot = 100;
int max = 100;
typedef NumericVector::iterator vec_iterator;
vec_iterator ixx = xx.begin();
vec_iterator ires = res.begin();
for (int i = 0; i < n; i++) {
if (ixx[i] != 0) {
processing = 1;
if (toggle == 1) {
ires[i] = 0;
} else {
tot += ixx[i];
if (tot > max) {
max = tot;
} else if (.98 * max > tot) {
toggle = 1;
}
}
}
if (ixx[i] == 0 && processing == 1) {
tot = 100;
max = 100;
toggle = 0;
}
}
return res;
'
foo.rcpp <- cxxfunction(signature(x = "numeric"), src, plugin = "Rcpp")
现在我们可以测试我们得到了预期的结果:
## demonstrate equivalence
d <- c(0,0,0,1,3,4,5,-1,2,3,-5,8,0,0,-2,-3,3,5,0,0,0,-1,-1,-1,-1)
all.equal(foo.r(d), foo.rcpp(d))
d
最后,通过重复 10e4 次来创建一个更大的版本。然后我们可以运行三个不同的函数,纯R
代码、编译R
代码和R
链接c++
代码的函数。
## make larger vector to test performance
dbig <- rep(d, 10^5)
system.time(res.r <- foo.r(dbig))
system.time(res.rcomp <- foo.rcomp(dbig))
system.time(res.rcpp <- foo.rcpp(dbig))
在我的系统上,给出:
> system.time(res.r <- foo.r(dbig))
user system elapsed
12.55 0.02 12.61
> system.time(res.rcomp <- foo.rcomp(dbig))
user system elapsed
2.17 0.01 2.19
> system.time(res.rcpp <- foo.rcpp(dbig))
user system elapsed
0.01 0.00 0.02
编译后的代码对 250 万向量进行运算R
所需时间约为未编译代码的 1/6 。即使编译后的代码只需要 0.02 秒即可完成,R
该代码的速度也快了几个数量级。除了初始设置之外,基本循环的语法几乎相同,因此您甚至不会失去清晰度。我怀疑即使您的部分或全部循环可以在. 最后,只是为了证明:c++
R
R
c++
R
R
c++
> all.equal(res.r, res.rcomp)
[1] TRUE
> all.equal(res.r, res.rcpp)
[1] TRUE
不同的函数返回相同的结果。