我正在尝试计算以下值:
1/N * sum[i=0 to N-1]( log(abs(r_i - 2 * r_i * x_i)) )
其中x_i是递归计算:
x_{i+1} = r_i * x_i * (1 - x_i)
在给出所有r_i
的情况下(尽管它们随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)
}
现在它自己的功能非常快,但我想称它为4,000,000次(2000 x 2000矩阵中的每个单元一次),每个都有不同的{{ 1}}向量。
但是,如果我将其称为偶数2500次(N = 1000),则需要约25秒,具有以下配置文件:
rs
是否有人知道如何加快速度?看起来乘法需要一段时间,但我已经预先缓存了任何重复的乘法。
我还尝试利用 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
与sum( log(stuff(i)) )
相同来减少对log(prod(stuff(i))
和log
的调用,但结果却不可行{{1} }是一个长度为abs
(数千)且典型值至少为1的向量,因此stuff
最终为N
到R。
答案 0 :(得分:5)
在我看来,瓶颈是你职能中的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))
在我上一次测试中, f1
比f
快140倍。