2

我正在尝试计算以下值:

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_is 都被给出(尽管它们随着 改变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 矩阵中的每个单元格一次),每个都有不同的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

有谁知道我如何加快速度?看起来乘法需要一段时间,但我已经预先缓存了任何重复的乘法。

我还尝试利用 与减少对and的调用sum( log(stuff(i)) )相同的优势,但结果证明这是不可行的,因为长度向量(以千计)和典型值至少为 1,因此最终成为R。log(prod(stuff(i))logabsstuffNprod(stuff)Inf

4

1 回答 1

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))

f1f我上次测试的速度快 140 倍。

于 2013-01-24T07:25:39.800 回答