我正在尝试计算以下值:
1/N * sum[i=0 to N-1]( log(abs(r_i - 2 * r_i * x_i)) )
Run Code Online (Sandbox Code Playgroud)
其中x_i以递归方式计算:
x_{i+1} = r_i * x_i * (1 - x_i)
Run Code Online (Sandbox Code Playgroud)
在r_i给出所有s的情况下(尽管它们随之变化i),并且x_0给出了.(据我所知,没有一种棘手的数学方法可以将这种计算简化为非迭代公式,以加快它的速度).
我的问题是它很慢,我想知道一些外部视角是否可以帮助我加快速度.
# x0: a scalar. rs: a numeric vector, length N
# N: typically ~5000
f <- function (x0, rs, N) {
lambda <- 0
x <- x0
for (i in 1:N) {
r <- rs[i]
rx <- r * x
lambda <- lambda + log(abs(r - 2 * rx))
# calculate the next x value
x <- rx - rx * x
}
return(lambda / N)
}
Run Code Online (Sandbox Code Playgroud)
现在它自己的功能相当快,但我想称它为4,000,000次(2000 x 2000矩阵中的每个单元一次),每个都有不同的rs向量.
但是,如果我将它称为偶数2500次(N = 1000),则需要约25秒,具有以下配置文件:
self.time self.pct total.time total.pct
"f" 19.98 81.22 24.60 100.00
"*" 2.00 8.13 2.00 8.13
"-" 1.32 5.37 1.32 5.37
"+" 0.70 2.85 0.70 2.85
"abs" 0.56 2.28 0.56 2.28
":" 0.04 0.16 0.04 0.16
Run Code Online (Sandbox Code Playgroud)
有谁知道我怎么可能加快这个速度?看起来乘法需要一段时间,但我已经预先缓存了任何重复的乘法.
我也试图利用与减少对和的调用sum( log(stuff(i)) )相同的优势 ,但结果是不可行的,因为是长度的矢量(以千为单位)和典型值至少为1,所以最终是为了R.log(prod(stuff(i))logabsstuffNprod(stuff)Inf
在我看来,瓶颈是for你的功能循环.
我用Rcpp重写它如下:
# x0: a scalar. rs: a numeric vector, length N
# N: typically ~5000
x0 <- runif(1)
N <- 5000
rs <- rnorm(5000)
f <- function (x0, rs, N) {
lambda <- 0
x <- x0
for (i in 1:N) {
r <- rs[i]
rx <- r * x
lambda <- lambda + log(abs(r - 2 * rx))
# calculate the next x value
x <- rx - rx * x
}
return(lambda / N)
}
library(inline)
library(Rcpp)
f1 <- cxxfunction(sig=c(Rx0="numeric", Rrs="numeric"), plugin="Rcpp", body='
double x0 = as<double>(Rx0);
NumericVector rs(Rrs);
int N = rs.size();
double lambda = 0, x = x0, r, rx;
for(int i = 0;i < N;i++) {
r = rs[i];
rx = r * x;
lambda = lambda + log( fabs(r - 2 * rx) );
x = rx - rx * x;
}
lambda /= N;
return wrap(lambda);
')
f(x0, rs, N)
f1(x0, rs)
library(rbenchmark)
benchmark(f(x0, rs, N), f1(x0, rs))
Run Code Online (Sandbox Code Playgroud)
f1比f我上次测试快140倍.