有人知道R中的replicate()函数是如何工作的,相对于使用for循环,它的效率如何?
例如,以下两种方式是否有效率差异...
means <- replicate(100000, mean(rnorm(50)))
并且...
means <- c()
for(i in 1:100000) {
means <- c(means, mean(rnorm(50)))
}
(上面的内容可能有些错误,但您可以理解我的意思。)
有人知道R中的replicate()函数是如何工作的,相对于使用for循环,它的效率如何?
例如,以下两种方式是否有效率差异...
means <- replicate(100000, mean(rnorm(50)))
并且...
means <- c()
for(i in 1:100000) {
means <- c(means, mean(rnorm(50)))
}
你只需要对代码进行基准测试并凭经验得出答案。请注意,我还添加了第二种for循环形式,通过预先分配向量来规避增长向量的问题。
repl_function = function(no_rep) means <- replicate(no_rep, mean(rnorm(50)))
for_loop = function(no_rep) {
means <- c()
for(i in 1:no_rep) {
means <- c(means, mean(rnorm(50)))
}
means
}
for_loop_prealloc = function(no_rep) {
means <- vector(mode = "numeric", length = no_rep)
for(i in 1:no_rep) {
means[i] <- mean(rnorm(50))
}
means
}
no_loops = 50e3
benchmark(repl_function(no_loops),
for_loop(no_loops),
for_loop_prealloc(no_loops),
replications = 3)
test replications elapsed relative user.self sys.self
2 for_loop(no_loops) 3 18.886 6.274 17.803 0.894
3 for_loop_prealloc(no_loops) 3 3.209 1.066 3.189 0.000
1 repl_function(no_loops) 3 3.010 1.000 2.997 0.000
user.child sys.child
2 0 0
3 0 0
1 0 0
看着 relative
这一列,未预分配内存的循环比预分配内存的循环慢了6.2倍。然而,预分配内存的循环和 replicate
一样快。
replicate
是sapply
的包装器,而sapply
本身是lapply
的包装器。 lapply
最终是一个用C编写的.Internal
函数,以一种优化的方式执行循环,而不是通过解释器。它的主要优点是高效的内存管理,特别是与您上面提出的高度低效的向量增长方法相比。
replicate
有着非常不同的体验,这也让我感到困惑。当我使用replicate
时,经常会导致我的R崩溃和笔记本电脑挂起,而相比之下,for
并没有出现这种情况,这让我感到惊讶。因为如上所述的原因,我也期望由C编写的函数能够优于for
循环。例如,如果您执行以下函数,您会发现for
循环比replicate
更快。system.time(for (i in 1:10) runif(1e7))
# user system elapsed
# 3.340 0.218 3.558
system.time(replicate(10, runif(1e7)))
# user system elapsed
# 4.622 0.484 5.109
因此,使用10
个复制品,循环速度显然更快。如果您将其重复100次,您将获得类似的结果。因此,我想知道是否有人可以提供一个示例,显示它与for
相比的实际优势。
另外,我还为runif(1e7)
创建了一个函数,在比较中没有任何区别。基本上,我未能提供任何显示replicate
优势的示例。
for loop
中,每次返回runif(1e7)
,而在replicate
中,你还将结果存储到一个大小为1e7 x 10
的矩阵中。 - George Pipis向量化是它们之间的关键区别。我将尝试解释这一点。R是一种高级解释型计算机语言。它为您处理许多基本的计算机任务。当您编写代码时,
x <- 2.0
你不需要告诉你的电脑:
R会自己解决这些问题。
但是,对于这样舒适的问题,有一个代价:它比低级语言慢。
在C或FORTRAN中,许多“test if”都会在编译步骤中完成,而不是在程序执行期间完成。它们在编写后被翻译成二进制计算机语言(0/1),但在运行之前。这使得编译器可以以最优方式组织二进制机器代码供计算机解释。
这与R中的向量化有什么关系?嗯,许多R函数实际上是用编译语言(如C、C++和FORTRAN)编写的,并具有小的R“包装器”。这就是你的方法与众不同的地方。for
循环添加了更多的test if
操作,使机器在数据上执行时变慢。
replicate
一样快。我认为这是因为代码的主要部分在R中花费了大量时间。重新实现整个循环,例如在C++中使用mean
,可能会显著加速。请参见我的答案中的基准测试。 - Paul Hiemstra