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/cn.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灯, 水草

请输入看板名称,例如:e-shopping站内搜寻

TOP