R_Language 板


LINE

[關鍵字]: R, loop 網誌版: http://wush.ghost.io/itertools-intro/ --- # itertools 簡介 Wush Wu March 10, 2017 最近在ptt R_Language版上看到許多跟迴圈有關的文章,所以一時興起想跟大家分享寫迴 圈或apply等函數好用的套件:itertools ```r library(itertools) ``` ``` ## Loading required package: iterators ``` 講itertools之前,要先介紹iterator的概念:這是把迴圈的功能更精鍊出來的概念。 我們先看一個迴圈的範例: ```r for(i in 1:3) { print(i) } ``` ``` ## [1] 1 ## [1] 2 ## [1] 3 ``` 這段迴圈的靈魂,在於變數`i`。透過`i in 1:3`,R 就知道`i`的值有以下規則: - 從`1`開始 - 每次遞增1 - 到`3`結束 更一般來說,R 的迴圈是透過一個Vector物件,告訴R要如何執行迴圈。舉例來說,`i in x`即代表: - 從`x[1]`開始 - `x[i]`結束之後執行`x[i+1]` - 到`x[length(x)]`結束 但是我們可以再更精鍊這樣的概念。而許多工具中,就會設計`iterator`這樣的物件,並 且讓他具備以下兩種功能 - 有沒有下一個值 - 取出下一個值,並且往前推進 有這兩個概念即可建立一個迴圈。 舉例來說,以下兩個迴圈是等價的: ```r for(i in 1:3) { print(i) } ``` ``` ## [1] 1 ## [1] 2 ## [1] 3 ``` ```r i <- 0 while(i < 3) { i <- i + 1 print(i) } ``` ``` ## [1] 1 ## [1] 2 ## [1] 3 ``` 這裡的`i < 4`代表`有沒有下一個值`的邏輯判斷,而`i <- i + 1`則代表`取出下一個值 ,並且往前推進`。 itertools套件會建立符合上述概念的物件,並稱之為`iterator`。 透過iterator之間的運算,我們可以輕鬆寫出複雜的迴圈結構 ## 範例一:雙層迴圈 有時候當我們需要走遍整個矩陣時,我們可能會寫出類似以下程式碼的迴圈結構: ```r for(i in 1:3) { for(j in 1:3) { print(paste(i, j)) } } ``` ``` ## [1] "1 1" ## [1] "1 2" ## [1] "1 3" ## [1] "2 1" ## [1] "2 2" ## [1] "2 3" ## [1] "3 1" ## [1] "3 2" ## [1] "3 3" ``` 運用itertools時,我們可以透過`product`來產生相同的效果: ```r it <- ihasNext(product(i = 1:3, j = 1:3)) while(hasNext(it)) { x <- nextElem(it) print(paste(x$i, x$j)) } ``` ``` ## [1] "1 1" ## [1] "1 2" ## [1] "1 3" ## [1] "2 1" ## [1] "2 2" ## [1] "2 3" ## [1] "3 1" ## [1] "3 2" ## [1] "3 3" ``` itertools產生的iterator不能直接在for之中使用,必須要搭配`ihasNext`、`hasNext` 與`nextElem`來做出上述概念的程式碼。 但是我們可以直接拿iterator與`lapply`搭配: ```r result <- lapply(product(i = 1:3, j = 1:3), function(x) { print(paste(x$i, x$j)) }) ``` ``` ## [1] "1 1" ## [1] "1 2" ## [1] "1 3" ## [1] "2 1" ## [1] "2 2" ## [1] "2 3" ## [1] "3 1" ## [1] "3 2" ## [1] "3 3" ``` ## 範例二: 合併迴圈 有時候我們有兩個vector要一起做迴圈,這時候只能透過對座標做迴圈來達成。舉例來 說: ```r x <- 1:3 y <- 4:6 for(i in seq_along(x)) { print(paste(x[i], y[i])) } ``` ``` ## [1] "1 4" ## [1] "2 5" ## [1] "3 6" ``` 但是這種程式碼在x, y 長度不同時不一定會出錯。 運用itertools時,我們可以透過`izip`來產生相同的效果: ```r it <- ihasNext(izip(x = 1:3, y = 4:6)) while(hasNext(it)) { x <- nextElem(it) print(paste(x$x, x$y)) } ``` ``` ## [1] "1 4" ## [1] "2 5" ## [1] "3 6" ``` ## 範例三: data.frame 在使用data.frame時,我們常常想要把data.frame的row走一遍: ```r df <- iris[1:3,] for(i in seq_len(nrow(df))) { x <- df[i,] print(paste(x$Sepal.Length, x$Sepal.Width, x$Petal.Length, x$Petal.Width, x$Species)) } ``` ``` ## [1] "5.1 3.5 1.4 0.2 setosa" ## [1] "4.9 3 1.4 0.2 setosa" ## [1] "4.7 3.2 1.3 0.2 setosa" ``` 而itertools可以直接指定走的方向: ```r it <- ihasNext(iter(iris[1:3,], by = "row")) while(hasNext(it)) { x <- nextElem(it) print(paste(x$Sepal.Length, x$Sepal.Width, x$Petal.Length, x$Petal.Width, x$Species)) } ``` ``` ## [1] "5.1 3.5 1.4 0.2 setosa" ## [1] "4.9 3 1.4 0.2 setosa" ## [1] "4.7 3.2 1.3 0.2 setosa" ``` ## 範例四: 批次迴圈 itertools也可以建立批次處理的迴圈: ```r it <- ihasNext(ichunk(1:10, 3)) while (hasNext(it)) { print(unlist(nextElem(it))) } ``` ``` ## [1] 1 2 3 ## [1] 4 5 6 ## [1] 7 8 9 ## [1] 10 ``` ## 範例四: 截斷迴圈 itertools也可以控制讓迴圈提早中止: ```r mkfinished <- function(time) { starttime <- proc.time()[3] function() proc.time()[3] > starttime + time } f <- mkfinished(1) # 這是個函數,當時間比這個瞬間晚1秒時,f就會回傳FALSE, 迴圈 會中止 # 看看1秒內,迴圈可以跑多少 length(lapply(ibreak(iter(1:1000000), f), function(x) { # do something })) ``` ``` ## [1] 25499 ``` 為了更簡單的使用時間限制的功能,itertools提供了`timeout` ```r it <- ihasNext(timeout(iter(1:1000000), 1)) count <- 0 while(hasNext(it)) { x <- nextElem(it) count <- count + 1 } count ``` ``` ## [1] 17932 ``` 也可以給定長度,截斷迴圈 ```r length(lapply(ilimit(iter(1:1000000), 100), function(x) { # do something })) ``` ``` ## [1] 100 ``` ## 範例五: 重複迴圈 我們也可以重複一個iterator若干次,甚至是無限次 ```r it <- ihasNext(recycle(iter(1:3), 2)) while(hasNext(it)) { x <- nextElem(it) print(x) } ``` ``` ## [1] 1 ## [1] 2 ## [1] 3 ## [1] 1 ## [1] 2 ## [1] 3 ``` ## 總結 以上我們展示了一些itertools提供的部份功能。它還有其他有趣的功能可以探索。 總之,當R友們在寫迴圈時,如果遇到比較複雜的迴圈情境,建議可以看看itertools這個 套件有沒有提供幫助。 --



※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 1.161.227.161
※ 文章網址: https://webptt.com/m.aspx?n=bbs/R_Language/M.1489136959.A.CD4.html ※ 編輯: Wush978 (1.161.227.161), 03/10/2017 17:34:51 ※ 編輯: Wush978 (1.161.227.161), 03/10/2017 18:37:53
1F:推 Neisseria: 蠻有 func lang 的 fu,走 itertools 效能會比較好嗎? 03/10 18:46
2F:推 obarisk: 把所有東西都做成map, reduce不是很好嗎(誤) 03/10 18:58
3F:推 celestialgod: 推 03/10 19:08
4F:推 locka: 感謝介紹!讓程式寫起來更簡潔,不過同樣好奇效能XD 03/10 19:48
5F:→ Wush978: 都寫for loop了還要在乎效能嘛?(誤) 03/10 20:04
6F:推 cywhale: 推 很有意思,多謝分享~~ 03/10 20:16
7F:推 criky: 推一個~也好奇效能 XD 03/11 09:58
在網誌上做了測試並給了comment: http://wush.ghost.io/itertools-performance/ 這裡只貼重點不貼原文了(每次貼每次當) ```r f1 <- function() { lapply(1:100, function(i) { lapply(1:100, function(j) { }) }) NULL } f2 <- function() { lapply(product(i = 1:100, j = 1:100), function(x) { }) NULL } microbenchmark(f1(), f2(), times = 10) ``` ``` ## Unit: milliseconds ## expr min lq mean median uq max ## f1() 4.657429 5.329925 6.092346 5.896559 6.685231 8.482395 ## f2() 466.092096 485.819743 504.164424 500.838942 522.266778 538.185611 ## neval ## 10 ## 10 ``` 在我的電腦上,差不多是5 vs 500 milliseconds 的差異,也就是100倍。 看起來很多, 可是在實務上呢? 如果# do something每次花1 milli seconds做計算,那整體的時間差異也是: 10000 + 5 v.s. 10000 + 500, 而在10000面前,你不太會注意到那100倍的差距。 就我自己用itertools的經驗時,通常是在寫一些不是效能很重要的程式碼。ps. 效能重 要的程式碼我會用C++寫。 有時候,當寫一個只會跑若干次的程式時,為了省那不到一秒 的時間,而去寫更難寫更複雜的程式碼,反而花更多時間,並且得不償失阿。 所以我在 看到一些R友問效能的時候,心裡其實是感到滿訝異的: 大家是不是走火入魔了? 並不是 只有跑得快才有價值,有的時候能把程式碼弄的更簡單,也是很有價值的。而這個套件的 價值,偏向後者。 ※ 編輯: Wush978 (1.163.178.151), 03/11/2017 16:19:43
8F:推 a78998042a: 推 03/14 00:29







like.gif 您可能會有興趣的文章
icon.png[問題/行為] 貓晚上進房間會不會有憋尿問題
icon.pngRe: [閒聊] 選了錯誤的女孩成為魔法少女 XDDDDDDDDDD
icon.png[正妹] 瑞典 一張
icon.png[心得] EMS高領長版毛衣.墨小樓MC1002
icon.png[分享] 丹龍隔熱紙GE55+33+22
icon.png[問題] 清洗洗衣機
icon.png[尋物] 窗台下的空間
icon.png[閒聊] 双極の女神1 木魔爵
icon.png[售車] 新竹 1997 march 1297cc 白色 四門
icon.png[討論] 能從照片感受到攝影者心情嗎
icon.png[狂賀] 賀賀賀賀 賀!島村卯月!總選舉NO.1
icon.png[難過] 羨慕白皮膚的女生
icon.png閱讀文章
icon.png[黑特]
icon.png[問題] SBK S1安裝於安全帽位置
icon.png[分享] 舊woo100絕版開箱!!
icon.pngRe: [無言] 關於小包衛生紙
icon.png[開箱] E5-2683V3 RX480Strix 快睿C1 簡單測試
icon.png[心得] 蒼の海賊龍 地獄 執行者16PT
icon.png[售車] 1999年Virage iO 1.8EXi
icon.png[心得] 挑戰33 LV10 獅子座pt solo
icon.png[閒聊] 手把手教你不被桶之新手主購教學
icon.png[分享] Civic Type R 量產版官方照無預警流出
icon.png[售車] Golf 4 2.0 銀色 自排
icon.png[出售] Graco提籃汽座(有底座)2000元誠可議
icon.png[問題] 請問補牙材質掉了還能再補嗎?(台中半年內
icon.png[問題] 44th 單曲 生寫竟然都給重複的啊啊!
icon.png[心得] 華南紅卡/icash 核卡
icon.png[問題] 拔牙矯正這樣正常嗎
icon.png[贈送] 老莫高業 初業 102年版
icon.png[情報] 三大行動支付 本季掀戰火
icon.png[寶寶] 博客來Amos水蠟筆5/1特價五折
icon.pngRe: [心得] 新鮮人一些面試分享
icon.png[心得] 蒼の海賊龍 地獄 麒麟25PT
icon.pngRe: [閒聊] (君の名は。雷慎入) 君名二創漫畫翻譯
icon.pngRe: [閒聊] OGN中場影片:失蹤人口局 (英文字幕)
icon.png[問題] 台灣大哥大4G訊號差
icon.png[出售] [全國]全新千尋侘草LED燈, 水草

請輸入看板名稱,例如:WOW站內搜尋

TOP