简体   繁体   English

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

[英]How to make a loop run faster in R?

I want to use arms() to get one sample each time and make a loop like the following one in my function. 我想使用arms()每次获取一个样本,并在函数中进行如下循环。 It runs very slowly. 它运行非常缓慢。 How could I make it run faster? 我怎样才能使其运行更快? Thanks. 谢谢。

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

This is a version based on Tommy's answer but avoiding all loops: 这是基于汤米答案的版本,但避免了所有循环:

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

On a multicore machine this will be really fast since it spreads the loads across cores. 在多核计算机上,这将非常快,因为它将负载分散到各个核中。 On a single-core machine (or for poor Windows users) you can replace mclapply above with lapply and get only a slight speedup compared to Tommy's answer. 在单核计算机上(或针对Windows用户),您可以用mclapply替换上面的lapply并且与Tommy的答案相比,只会稍微提高一点速度。 But note that the result will be different for parallel versions since it will use different RNG sequences. 但是请注意,并行版本的结果将有所不同,因为它将使用不同的RNG序列。

Note that any C code that needs to evaluate R functions will be inherently slow (because interpreted code is slow). 请注意,任何需要评估R函数的C代码本质上都会很慢(因为解释后的代码很慢)。 I have added the arms.C just to remove all R->C overhead to make moli happy ;), but it doesn't make any difference. 我添加了arms.C只是为了消除所有R-> C开销,以使moli开心;),但这没有任何区别。

You could squeeze out a few more milliseconds by using column-major processing (the question code was row-major which requires re-copying as R matrices are always column-major). 您可以通过使用以列为主的处理方式来压缩几毫秒(问题代码是以行为主的,由于R矩阵始终以列为主,因此需要重新复制)。

Edit: I noticed that moli changed the question slightly since Tommy answered - so instead of the sum(...) part you have to use a loop since y[i] are dependent, so the function(z) would look like 编辑:自汤米回答以来,我注意到莫利稍微改变了问题-因此,由于y[i]是依赖的,因此您必须使用循环,而不是sum(...)部分,因此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 }

Well, one effective way is to get rid of the overhead inside arms . 嗯,一种有效的方法是摆脱arms内部的开销。 It does some checks and calls the indFunc every time even though the result is always the same in your case. 即使您的结果始终相同,它indFunc一些检查并每次都调用indFunc Some other evaluations can be also be done outside the loop. 也可以在循环外进行其他一些评估。 These optimizations bring down the time from 54 secs to around 6.3 secs on my machine. 这些优化使我的机器上的时间从54秒减少到6.3秒左右。 ...and the answer is identical. ...答案是相同的。

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

why not like this? 为什么不这样呢?

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

However, its still single core and time consuming. 但是,它仍然是单核且耗时的。 But that isn't R being slow, its the arms function. 但这不是R慢,而是其手臂功能。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM