2012-05-06 46 views
14

我知道使用for循環並不是R中的最佳做法,因爲它沒有增強的性能。幾乎所有的情況下,都有家庭*apply的功能,解決了我們的問題。R中的循環 - 需要使用索引,無論如何避免'for'?

但是我面臨的情況是我沒有看到解決方法。

我需要計算連續值的百分比變化:

pv[1] <- 0 
for(i in 2:length(x)) { 
    pv[i] <- (x[i] - x[i-1])/x[i-1] 
} 

所以,你可以看到,我必須同時使用x[i]元素,也是x[i-1]元素。通過使用*apply函數,我只看到如何使用x[i]。無論如何,我可以避免for循環?

回答

18

你提出的建議將是分數的變化,但如果乘以100,你得到的 「百分比變化」:

pv<- vector("numeric",length(x)) 
pv[1] <- 0 
pv[-1] <- 100* (x[-1] - x[-length(x)])/ x[-length(x)] 

矢量化的解決方案。 (你應該注意到for循環將會像應用解決方案一樣慢......只是不太漂亮,總是尋找一種向量化的方法。)

解釋更多一點:x[-length(x)]是向量,x[1:(length{x-1)]x[-1]是向量,x[2:length(x)],並且R中的向量操作與在for循環體中執行的操作相同,但不使用顯式循環。 R首先在這些移位向量中構建差異,,然後除以x[1:(length{x-1)]

+0

好的迴應迪文。我實際上並不知道海報的完成情況,但我在矢量化方面達成了100%的一致。+1 –

+0

非常好的答案!我不知道矢量化的方法是最快的,我認爲'lapply'是。但是在最後一行代碼中,不應該是'x [-1] - x [-length(x)]'? –

+0

@JoãoDaniel:是的,應該的。編輯應用。 –

20

你可以得到相同的結果:

pv <- c(0) 
y <- sapply(2:length(x), function(i) {pv <<- (x[i] - x[i-1])/x[i-1]}) 
c(0, y) 

的對於曾經是一個問題都得到了優化環路的問題。通常,for循環不會更慢,甚至可能比適用解決方案更快。你必須對它們進行測試並看看。我打賭你的for循環比我的解決方案更快。

編輯:只是爲了說明for循環與應用解決方案以及什麼迪文討論關於矢量化我跑在四個解決方案上使用microbenchmark在贏得7機器上的基準。

Unit: microseconds 
      expr  min  lq median  uq  max 
1 DIFF_Vincent 22.396 25.195 27.061 29.860 2073.848 
2  FOR.LOOP 132.037 137.168 139.968 144.634 56696.989 
3   SAPPLY 146.033 152.099 155.365 162.363 2321.590 
4 VECTORIZED_Dwin 18.196 20.063 21.463 23.328 536.075 

enter image description here

+0

什麼是「DIF」版本的,什麼是整個測試是什麼樣子? @VincentZoonekynd的解決方案對我來說運行速度最快。 – Tommy

+0

應該是DIFF差異(文森特的)。爲了公平對待他,基準測試不要忘記從迪文的解決方案中取出* 100,因爲這增加了百分之一的額外計算(不是像所有人一樣的比例eles的解決方案)。 –

+0

+1爲圖的美麗! –

16

您還可以使用diff

c(0, diff(x)/x[-length(x)]) 
c(0, exp(diff(log(x))) - 1) 
+0

+1這似乎是最快的......而且我喜歡log/exp變體,儘管速度並不快。 – Tommy

+0

帽子提示:我不得不承認diff()方法比我直接轉換爲矢量化解決方案稍微優雅。我很驚訝它沒有更好的基準。 –

+0

@DWin - 當我進行基準測試時,使用diff或不是沒有區別。但用'c'代替你的替換要快得多。 Tyler的數字有點可疑。我在'x < - runif(1e7)'上運行它...... – Tommy