2012-11-16 63 views
6

有誰知道R中的replicate()函數是如何工作的以及它相對於使用for循環的效率如何?複製()與for循環?

例如,是否有任何之間的效率差異的...

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

而且......

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

(我可能鍵入一些稍微偏離上面,但你的想法。 )

回答

14

您可以對代碼進行基準測試並根據經驗得出答案。請注意,我還添加了第二個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一樣快。

8

replicatesapply的包裝,它本身是lapply的包裝。 lapply最終是一個用C語言編寫的.Internal函數,並以優化的方式執行循環,而不是通過解釋器。它的主要優點是高效的內存管理,特別是與上面介紹的非常低效的向量增長方法相比。

+1

預分配for循環與「replicate」一樣快。我認爲這是因爲代碼的主要部分是在R中花費的。例如,在「mean」周圍重新實現整個循環。 C++可能會加快速度。看到我的答案中的基準。 –

1

我與replicate有一個非常不同的經驗,這也使我困惑。當我使用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優勢的例子。

1

矢量化是它們之間的關鍵區別。我會托盤解釋這一點。 R是一種高級解釋的計算機語言。它爲您處理許多基本的計算機任務。當你寫

x <- 2.0 

你不必告訴您的計算機

  • 「2.0」是一個浮點數;
  • 「x」應該存儲數字型數據;
  • 它必須在內存中找到放置「5」的位置;
  • 它必須註冊「x」作爲指向內存中某個地方的指針。

R自己計算這些東西。

但是,爲了這樣舒適的問題,有一個價格:它比低級語言慢。

在C或FORTRAN中,大部分此「測試if」將在編譯步驟中完成,而不是在程序執行過程中完成。它們在寫入之後被翻譯成二進制計算機語言(0/1),但在它們運行之前。這允許編譯器以計算機解釋的最佳方式組織二進制機器代碼。

這與R中的矢量化有什麼關係?那麼,許多R函數實際上是用一種編譯語言編寫的,比如C,C++和FORTRAN,並且有一個小的R「包裝器」。這是你方法的區別。 for循環進一步添加test if機器必須對數據執行的操作,使其變得更慢