2009-07-23 19 views

回答

2

對於R中循環是出了名的慢,但這裏還有另外一個問題。預先分配結果向量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 

而且,Sharpie points out,我們可以通過使用像apply(或其親屬,sapplylapply)R功能,使這稍微快一些。

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 
+0

R列表中的第二個答案有什麼問題:res < - rnorm(10^6)-rnorm(10^6)? – ars 2009-07-23 05:07:58

+0

@ars:你絕對是對的 - 這給出了最快的解決方案(一個數量級)。最好的建議是1.使用對矢量自然工作的函數(如rnorm); 2.如果失敗,則使用* apply函數;如果做不到這一點,請使用帶預分配的for循環。 – 2009-07-23 08:03:34

9

循環的效率能夠被極大R中通過使用的應用功能,其基本上在處理數據的整個矢量一次,而不是通過它們循環增加。對於上面所示的循環中,有兩個基本的操作在每次迭代期間發生:

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

# The difference between those numbers is calculated 
x[2] - x[1] 

在這種情況下適當的功能將是sapply()sapply()操作對象,如由循環語句1:N產生的矢量的名單上,並返回結果的載體:

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

注意,在函數調用期間的指數值i可用且連續取值爲在1N之間,但是在這種情況下不需要。

進入承認其中apply可以通過for使用是一個非常有價值skill-並行計算很多[R庫通過apply功能提供插件和播放並行的習慣。使用apply通常可以允許在多核系統上訪問顯着的性能增加,其中代碼重構的代價是

2

有時不需要循環。由於RNORM給IID樣品(理論上),你會得到相同的結果(採樣 X-Y其中X和Y是N(0,1))這樣做:

res <- rnorm(N)-rnorm(N) 
4

對我的評論擴大到chris_dubois的答案,這裏的一些定時信息:

> system.time(res <- rnorm(50000) - rnorm(50000)) 
user system elapsed 
0.06 0.00 0.06 

對比這與FN3來自同一個答案:

> system.time(res3 <- fn3(50000)) 
user system elapsed 
1.33 0.01 1.36 

首先要注意的是,我的膝蓋頂部比chris_dubois的機器慢。:)

第二個也是更重要的一點是,這裏非常適用的矢量方法速度要快一個數量級。 (Richie Cotton也在同一個答案的評論中指出)。

這使我最後的一點:它是一個神話apply它的朋友是比R. for環路他們在大多數測量我已經看到了同樣量級的速度要快得多。因爲他們只是幕後的for循環。也看到這個帖子:

http://yusung.blogspot.com/2008/04/speed-issue-in-r-computing-apply-vs.html

根據布萊恩·裏普利教授,「應用()僅僅是一個循環的包裝。」使用apply()的唯一好處是它使你的代碼更加整潔!

沒錯。如果更多,請使用apply富有表現力,尤其是如果您使用功能風格進行編程時。不是因爲它更快。

0

也許最有效的替代你的函數,簡直是:

fn <- function(n) rnorm(N,0,sqrt(2)) 

這是快兩倍,採取獨立同分布正常的變元的差異。更普遍的是,如果你的目標是運行簡單的模擬,向量/數組的預分配和調用本地函數將大大加速這個過程。

如果要爲統計估計(例如MCMC)執行monte-carlo模擬,則R有許多本地程序包。對於一般的隨機模擬,我不知道R軟件包,但你可能想嘗試Simpy(http://simpy.sourceforge.net/),這很好。