【问题标题】:Replicate() versus a for loop?Replicate() 与 for 循环?
【发布时间】:2012-11-04 22:13:19
【问题描述】:

有谁知道 R 中的 replicate() 函数是如何工作的,以及它相对于使用 for 循环的效率如何?

比如,有没有效率上的区别……

means <- replicate(100000, mean(rnorm(50)))

还有……

means <- c()
for(i in 1:100000) { 
   means <- c(means, mean(rnorm(50)))
}

(我可能在上面打了一些字,但你明白了。)

【问题讨论】:

    标签: performance r for-loop replicate


    【解决方案1】:

    您可以对代码进行基准测试并凭经验获得答案。请注意,我还添加了第二个 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 列,未预分配的 for 循环慢了 6.2 倍。但是,预分配的 for 循环与 replicate 一样快。

    【讨论】:

      【解决方案2】:

      replicatesapply 的包装器,它本身就是lapply 的包装器。 lapply 最终是一个 .Internal 函数,它是用 C 语言编写的,并以优化的方式执行循环,而不是通过解释器。它的主要优点是高效的内存管理,特别是与您上面介绍的非常低效的向量增长方法相比。

      【讨论】:

      • 预分配的 for 循环与 replicate 一样快。我认为这是因为代码的主要部分用在 R 中。重新实现围绕 mean 的整个循环,例如C++ 可能会加快速度。请参阅我的答案中的基准。
      【解决方案3】:

      我对@9​​87654321@ 有非常不同的体验,这也让我感到困惑。与for 相比,当我使用replicatefor 时,经常发生我的R 崩溃和我的笔记本电脑挂起的情况,这让我感到惊讶,由于上述原因,我还期望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 复制,for 循环显然更快。如果你重复 100 次,你会得到相似的结果。所以我想知道是否有人可以举一个例子来说明它与for相比的实用特权。

      PS 我还为runif(1e7) 创建了一个函数,这在比较中没有任何区别。基本上我没有提供任何显示replicate 优势的示例。

      【讨论】:

      • 我认为您的比较是不公平的,因为在 for loop 中,您每次都返回 runif(1e7),而在 replicateyou 中,您还将结果存储到 1e7 x 10 的矩阵中
      【解决方案4】:

      矢量化是它们之间的关键区别。我将托盘解释这一点。 R 是一种高级解释的计算机语言。它为您处理许多基本的计算机任务。当你写

      x <- 2.0
      

      您不必告诉您的计算机

      • “2.0”是一个浮点数;
      • “x”应该存储数字类型的数据;
      • 它必须在内存中找到一个位置来放置“5”;
      • 它必须将“x”注册为指向内存中某个位置的指针。

      R 自己计算这些东西。

      但是,对于这样舒适的问题,这是有代价的:它比低级语言慢。

      在 C 或 FORTRAN 中,大部分“测试是否”将在编译步骤中完成,而不是在程序执行期间完成。它们在编写后但在运行之前被翻译成二进制计算机语言 (0/1)。这允许编译器以最佳方式组织二进制机器代码以供计算机解释。

      这与 R 中的矢量化有什么关系?嗯,许多 R 函数实际上是用编译语言编写的,例如 C、C++ 和 FORTRAN,并且有一个小的 R“包装器”。这是您的方法之间的区别。 for 循环进一步添加了机器必须对数据执行的 test if 操作,使其变慢

      【讨论】:

        猜你喜欢
        • 2020-07-10
        • 1970-01-01
        • 1970-01-01
        • 2015-08-28
        • 2011-07-12
        • 2017-07-09
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多