標籤:

如何高效的在R里寫出一個循環?

不管在Python還是R,在代碼中使用循環都會極大的提升工作效率。作為一個初學小白,題主在寫循環的時候十分掙扎。希望知乎的朋友們能分享一下經驗,怎樣高效的寫出循環?


最新的 RStudio 有 snippet 功能…

兩種方法:

1. 打完 for 停頓 250 毫秒,等提示出現,按回車。

2. 打完 for 按 tab,等提示,回車。

哪種更高效取決於能不能在 250 毫秒內按下 tab。


謝邀。

少用for的循環,多用Python的list comprehension或map或reduce(通常跟lambda算式用在一起),或R中各樣的apply函數。

Python

List comprehension

a = [2*i for i in range (10)]

map / reduce

a = map(lambda i: 2*i, range(10))

from operator import add
print "sum = ", reduce(add, a)

R

mapply

a&<-mapply(function(i) 2*i, 0:9)

lapply

a&<-lapply(0:9, function(i) 2*i)

Reduce

Reduce(function(i1, i2) {i1+i2}, a)


performance - Why are loops slow in R?

這裡面的答案說得很清楚了,for慢的原因就是R的一切都是需要開銷,一個括弧,一個加減號,對比C來說,都是很慢的,而使用for則把這一切都放大了,累積起來,就顯得for慢了。

其實for沒有你想像中的慢,放心寫吧

影響性能的地方永遠是代碼中最慢的那一部分,千萬不要把程序的每一部分都優化一遍,如果你想把每一個for都想辦法優化,那都不用做其他事情了。。

現在我分享一下R語言程序優化的方法吧

如何找到最慢的部分?

可以使用
lineprof包找到。

當你使用lineprof包找到你最慢的部分,你可以嘗試的方法:

  • 進行向量化(向量化後還有個好處就是很容易並行化如:parallel包的ParApply)

  • 使用高效的包去加速你的程序,如(data.table dplyr等)
  • 可以考慮將那部分的代碼使用Rcpp重寫。

lineprof包的使用參考:R語言性能可視化lineprof

想要了解data.table可以參考:R語言data.table簡介 ,The data.table R package cheat sheet,R語言data.table速查手冊

如果想要了解並行化可以參考:R語言並行化基礎與提高

了解Rcpp可以參考:Rcpp · Advanced R.


不管在Python還是R,在代碼中使用循環都會極大的提升工作效率。

呃。。。然而並不是這樣,至少在R中(和Matlab),使用循環通常是程序運行效率殺手。寫R程序,要避免循環,盡量向量化。當你在「初學小白」的狀態時,其實很多問題都是可以向量化的。

另外,你的問題是如何「高效的寫出循環」,還是寫出高效的循環?前者沒有什麼特別,看看教程就好了。對於後者,大多數人的答案會是讓你向量化,因為R的循環就是很慢。對於真的無法向量化的循環(例如複雜的蒙特卡洛模擬),也會有一些小技巧,比如減少大矩陣/數據框的讀寫次數之類。

關於向量化可以搜索到很多相關文章,知乎也有一些回答,比如:

R語言在哪些情況下for循環可以避免? - R(編程語言)

有哪些向量化寫法讓你拍案叫絕? - 數據分析


Python寫的不多,主要說一下R。R的特點之一就是向量化運算,在解決問題的過程中,操作的單位不在是單個元素,而是這一類元素的一個有序集合,也就是向量。換句話說,當你用的for的時候,你在操作一個點,當你做向量化運算或者利用lapply時,你操作的是一條線。

體育老師教的語文,讓大家見笑了。說點實際的吧,為什麼for比lapply慢。R的for語句在R本身這個層面運行,向量化和lapply則是調運底層的C,自然lapply要快很多。


可以試試Rcpp, Rcpp像是橋樑鏈接C和R。 你可以在C中寫循環然後在R中調用它, 速度會有明顯提升。但如果數據量實在大那大概只能用cluster了。


方法:

1.預先設置好向量類型及長度

2.將條件在循環外判斷

3.盡量使用ifelse 替代if() else

4.盡量使用apply/sapply/各種apply

5.使用compiler包的cmpfun()

6.運用並行運算

開始舉栗子

---------------------------------------------------------------------------------------------------------------------------

R代碼:

test &<- data.frame(rnorm(12^5, 0, 2)) for(i in nrow(test)){ if(test[i,1] &> 0){
test[i,2] &<- "p" } else { test[i,2] &<- "n" } }

方法1:

test &<- data.frame(rnorm(12^5, 0, 2)) add_col &<- character(nrow(test)) # 預先定義類型與長度 for(i in nrow(test)){ if(test[i,1] &> 0){
add_col[i] &<- "p" } else { add_col[i] &<- "n" } } test &<- cbind(test, add_col)

方法2:

test &<- data.frame(rnorm(12^5, 0, 2)) condition &<- test[,1] &> 0 # 預先計算好條件值
test[condition, 2] &<- "p" test[!condition, 2] &<- "n"

方法3:

test &<- data.frame(rnorm(12^5, 0, 2)) for(i in nrow(test)){ ifelse(test[i,1] &> 0, test[i,2] &<- "p", test[i,2] &<- "n") #盡量用ifelse }

栗子舉不出來了,後面幾種方法沒怎麼用過。

詳情參考:Strategies to Speedup R Code


推薦閱讀:

如何用R語言匹配兩個表的數據?
r 如何更新,不需要重裝的手段進行更新?
R語言 安裝完軟體後如何進行界面語言的設置?
有哪些比較好的R語言網路視頻教程推薦?
如何理解R中因子(factor)的概念?

TAG:R編程語言 |