如何在R中使循环运行得更快?

时间:2012-02-09 18:47:41

标签: r loops

我想使用arms()每次获取一个样本,并在我的函数中创建一个类似于下一个循环的循环。它运行得非常慢。我怎么能让它跑得更快?感谢。

library(HI)    
dmat <- matrix(0, nrow=100,ncol=30)
system.time(
    for (d in 1:100){
        for (j in 1:30){
            y <- rep(0, 101)
            for (i in 2:100){

                y[i] <- arms(0.3, function(x) (3.5+0.000001*d*j*y[i-1])*log(x)-x,
                    function(x) (x>1e-4)*(x<20), 1)       
            }
        dmat[d, j] <- sum(y)
        }
    }
) 

3 个答案:

答案 0 :(得分:3)

这是一个基于Tommy答案的版本,但避免了所有循环:

library(multicore) # or library(parallel) in 2.14.x
set.seed(42)
m = 100
n = 30
system.time({
    arms.C <- getNativeSymbolInfo("arms")$address
    bounds <- 0.3 + convex.bounds(0.3, dir = 1, function(x) (x>1e-4)*(x<20))
    if (diff(bounds) < 1e-07) stop("pointless!")
    # create the vector of z values
    zval <- 0.00001 * rep(seq.int(n), m) * rep(seq.int(m), each = n)
    # apply the inner function to each grid point and return the matrix
    dmat <- matrix(unlist(mclapply(zval, function(z)
            sum(unlist(lapply(seq.int(100), function(i)
                .Call(arms.C, bounds, function(x) (3.5 + z * i) * log(x) - x,
                      0.3, 1L, parent.frame())
            )))
        )), m, byrow=TRUE)
}) 

在多核计算机上,这将非常快,因为它会在核心之间传播负载。在单核机器上(或对于不良的Windows用户),您可以用mclapply替换上面的lapply,并且与Tommy的答案相比,只能获得轻微的加速。但请注意,并行版本的结果会有所不同,因为它将使用不同的RNG序列。

请注意,任何需要评估R函数的C代码本身都会很慢(因为解释的代码很慢)。我添加了arms.C只是为了删除所有的R-&gt; C开销以使moli高兴;),但它没有任何区别。

你可以使用列主要处理来挤出几毫秒(问题代码是行主要的,需要重新复制,因为R矩阵总是列为主要的。)

编辑:我注意到自从Tommy回答后,moli稍微改变了这个问题 - 所以不要使用sum(...)部分,因为y[i]依赖于function(z)部分,所以function(z) { y <- 0 for (i in seq.int(99)) y <- y + .Call(arms.C, bounds, function(x) (3.5 + z * y) * log(x) - x, 0.3, 1L, parent.frame()) y } 看起来像

{{1}}

答案 1 :(得分:2)

嗯,一种有效的方法是摆脱arms内的开销。它会进行一些检查并每次调用indFunc,即使结果在您的情况下始终相同。 其他一些评估也可以在循环外完成。这些优化将我的机器上的时间从54秒减少到大约6.3秒。 ......答案是一样的。

set.seed(42)
#dmat2 <- ##RUN ORIGINAL CODE HERE##

# Now try this:
set.seed(42)
dmat <- matrix(0, nrow=100,ncol=30)
system.time({
    e <- new.env()
    bounds <- 0.3 + convex.bounds(0.3, dir = 1, function(x) (x>1e-4)*(x<20))
    f <- function(x) (3.5+z*i)*log(x)-x
    if (diff(bounds) < 1e-07) stop("pointless!")
    for (d in seq_len(nrow(dmat))) {
        for (j in seq_len(ncol(dmat))) {
            y <- 0
            z <- 0.00001*d*j
            for (i in 1:100) {
                y <- y + .Call("arms", bounds, f, 0.3, 1L, e)
            }
            dmat[d, j] <- y
        }
    }
}) 

all.equal(dmat, dmat2) # TRUE

答案 2 :(得分:0)

为什么不喜欢这个?

dat <- expand.grid(d=1:10, j=1:3, i=1:10)

arms.func <- function(vec) {
  require(HI)
  dji <- vec[1]*vec[2]*vec[3]
  arms.out <- arms(0.3, 
                   function(x,params) (3.5 + 0.00001*params)*log(x) - x,
                   function(x,params) (x>1e-4)*(x<20),
                   n.sample=1,
                   params=dji)

  return(arms.out)
}

dat$arms <- apply(dat,1,arms.func)

library(plyr)
out <- ddply(dat,.(d,j),summarise, arms=sum(arms))

matrix(out$arms,nrow=length(unique(out$d)),ncol=length(unique(out$j)))

然而,它仍然是单核和耗时。但这不是R慢,它的武器功能。