假设我想使用以下内容执行模拟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)
通过使用应用函数可以在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在函数调用期间可用并先后呈现的价值观1和N,但它是没有必要在这种情况下.
养成识别apply可以在哪里使用的习惯for是一项非常有价值的技能 - 许多用于并行计算的R库通过apply函数提供即插即用的并行化.使用apply往往可以允许访问与多核系统显著的性能提升零重构的代码.
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)