R中挂着大圈?

Chr*_*ois 7 for-loop r

假设我想使用以下内容执行模拟function:

fn1 <- function(N) {
  res <- c()
  for (i in 1:N) {
    x <- rnorm(2)
    res <- c(res, x[2]-x[1])
  }
  res
}
Run Code Online (Sandbox Code Playgroud)

对于非常大的N计算似乎挂起.有更好的方法吗?

(灵感来自:https://stat.ethz.ch/pipermail/r-help/2008-February/155591.html)

Sha*_*pie 9

通过使用应用函数可以在R中极大地增加循环的效率,这些函数基本上一次处理整个数据向量而不是循环遍历它们.对于上面显示的循环,每次迭代期间都会发生两个基本操作:

# A vector of two random numbers is generated
x <- rnorm( 2 )

# The difference between those numbers is calculated
x[2] - x[1]
Run Code Online (Sandbox Code Playgroud)

在这种情况下,适当的功能将是sapply().sapply()对对象列表进行操作,例如loop语句生成1:N的向量,并返回结果向量:

sapply( 1:N, function( i ){ x <- rnorm(2); return( x[2] - x[1] ) } )
Run Code Online (Sandbox Code Playgroud)

请注意,指数值i在函数调用期间可用并先后呈现的价值观1N,但它是没有必要在这种情况下.

养成识别apply可以在哪里使用的习惯for是一项非常有价值的技能 - 许多用于并行计算的R库通过apply函数提供即插即用的并行化.使用apply往往可以允许访问与多核系统显著的性能提升重构的代码.


Chr*_*ois 2

R 中的 for 循环是出了名的慢,但这里还有另一个问题。预分配结果向量 res 更快,而不是在每次迭代时追加到 res。

下面我们可以将上述版本的速度与仅以长度为 N 的向量 res 开头并在循环期间更改第 i 个元素的版本进行比较。

fn1 <- function(N) {
  res <- c()
  for (i in 1:N) {
     x <- rnorm(2)
     res <- c(res,x[2]-x[1])
  }
  res
}
fn2 <- function(N) {
  res <- rep(0,N)
  for (i in 1:N) {
     x <- rnorm(2)
     res[i] <- x[2]-x[1]
  }
  res
}
> N <- 50000
> system.time(res1 <- fn1(N))
   user  system elapsed 
  6.568   0.256   6.826 
> system.time(res2 <- fn2(N))
   user  system elapsed 
  0.452   0.004   0.496 
Run Code Online (Sandbox Code Playgroud)

另外,正如Sharpie 指出的那样apply,我们可以通过使用 R 函数(或其亲戚,sapplyand )来稍微加快速度lapply

fn3 <- function(N) {
  sapply( 1:N, function( i ){ x <- rnorm(2); return( x[2] - x[1] ) } )
}
> system.time(res3 <- fn3(N))
   user  system elapsed 
  0.397   0.004   0.397 
Run Code Online (Sandbox Code Playgroud)