加快重复的函数调用

mat*_*fee 2 r vectorization

我正在尝试计算以下值:

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

wus*_*978 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))
Run Code Online (Sandbox Code Playgroud)

f1f我上次测试快140倍.