R_Language 板


LINE

[关键字]: R, JSON, Streaming [重点摘要]: 这阵子我接了一个案子,要帮忙[核桃运算](http://www.macrodatalab.com/#/)开发他们 产品BigObject Analytics的R Client。恰巧,他们的RESTful API在捞资料的时候,吐回 来的格式是[jsonlines](http://jsonlines.org/): ``` {"Sepal.Length":"5.1","Sepal.Width":"3.5","Petal.Length":"1.4","Petal.Width":"0.2","Species":"setosa"} {"Sepal.Length":"4.9","Sepal.Width":"3.0","Petal.Length":"1.4","Petal.Width":"0.2","Species":"setosa"} {"Sepal.Length":"4.7","Sepal.Width":"3.2","Petal.Length":"1.3","Petal.Width":"0.2","Species":"setosa"} {"Sepal.Length":"4.6","Sepal.Width":"3.1","Petal.Length":"1.5","Petal.Width":"0.2","Species":"setosa"} {"Sepal.Length":"5.0","Sepal.Width":"3.6","Petal.Length":"1.4","Petal.Width":"0.2","Species":"setosa"} {"Sepal.Length":"5.4","Sepal.Width":"3.9","Petal.Length":"1.7","Petal.Width":"0.4","Species":"setosa"} ``` 由於负担起底层Client的责任,这是我第一次要正面迎战这样的资料。以前我遇到这种资 料,都是先乱七八糟的解掉,反正当下能用就好了。但是在写Client的时候,这样的解决 方法是不能让人满意的! ###### 乱七八糟的解法: ```r library(magrittr) src # 刚刚的文字资料 strsplit(src, "\n") %>% sapply(fromJSON) ``` 话说最近用`magrittr`的pipeline style写程式码真的上瘾了,害我写python的时候觉得 python更难用了... 而且还找不到这种pipeline style。抱歉扯远了! 所以在<del>不能漏气</del>驱使自己进步的动力下,我开始运用过去和JSON打交道的经 验简单研究一下,目前在R 之中,要如何漂亮的处理这类的资料。 ### R中处理JSON的套件 相信碰过这个问题的朋友不在少数,而大家的想法大概都类似:找个套件把问题解决掉就 好啦! 但是处理JSON的套件在R里面就有好几个,这里列出我用过的套件: - [rjson](https://cran.r-project.org/web/packages/rjson/index.html) - [RJSONIO](https://cran.r-project.org/web/packages/RJSONIO/index.html) - [jsonlite](https://cran.r-project.org/web/packages/jsonlite/index.html) 而三个套件都提供了`fromJSON`函数,而偏偏三个函数的`fromJSON`都不能用: #### rjson `rjson::fromJSON`只处理第一行,後面的资料就当成没看到了。 ``` > rjson::fromJSON(src) $Sepal.Length [1] "5.1" $Sepal.Width [1] "3.5" $Petal.Length [1] "1.4" $Petal.Width [1] "0.2" $Species [1] "setosa" ``` #### RJSONIO `RJSONIO::fromJSON`则回传了意味不明的一个... 东西? ``` > RJSONIO::fromJSON(src) # 中间太可怕了,已经删掉 Species "setosa\"}{\"Sepal.Length\":\"4.9\",\"Sepal.Width\":\"3.0\",\"Petal.Length\":\"1.4\",\"Petal.Width\":\"0.2\",\"Species\":\"setosa\"}{\"Sepal.Length\":\"4.7\",\"Sepal.Width\":\"3.2\",\"Petal.Length\":\"1.3\",\"Petal.Width\":\"0.2\",\"Species\":\"setosa\"}{\"Sepal.Length\":\"4.6\",\"Sepal.Width\":\"3.1\",\"Petal.Length\":\"1.5\",\"Petal.Width\":\"0.2\",\"Species\":\"setosa\"}{\"Sepal.Length\":\"5.0\",\"Sepal.Width\":\"3.6\",\"Petal.Length\":\"1.4\",\"Petal.Width\":\"0.2\",\"Species\":\"setosa\"}{\"Sepal.Len gth\":\"5.4\",\"Sepal.Width\":\"3.9\",\"Petal.Length\":\"1.7\",\"Petal.Width\":\"0.4\",\"Species\":\"setosa" ``` 由於太过惊吓,所以我只好赶快检查一下这东西到底是什麽: ```r > str(.Last.value) Named chr [1:5] "5.1" "3.5" "1.4" "0.2" ... - attr(*, "names")= chr [1:5] "Sepal.Length" "Sepal.Width" "Petal.Length" "Petal.Width" ... ``` 看起来是个... 长度五的向量??? 阿弥陀佛! #### jsonlite `jsonlite`则是直接喷错,简单明了! ```r > jsonlite::fromJSON(src) Error: parse error: trailing garbage h":"0.2","Species":"setosa"} {"Sepal.Length":"4.9","Sepal.Wi (right here) ------^ ``` 我其实比较喜欢这样子的风格:凡是不能处理的资料就喷错,不要像`rjson`一样不喷错 但是给<del>错误</del>不预期的结果。要是我没注意到有掉资料,直接用到产品之中, 就... ### 革命尚未成功,同志仍需努力 由於这种jsonlines格式的资料是非常非常的常见,所以如果R 没有处理这类函数的功能 ,也太扯了吧! 所以於是我就看了一下这三个套件有没有issues区可以讨论,而目前看起来,只有 `jsonlite`有上github。但是简单看一下目前有开的issues,居然没有要求这个套件处理 jsonlines!这通常表示,问题可能已经被解决了... 离题一下,在造访`jsonlite`套件的过程中,我也注意到原来`jsonlite`是`RJSONIO`的 继承者阿!喵了一下Reverse Depends、Reverse Imports的套件名单,看来都和Hadley大 大那帮人有扯上关系(httr、curl)。 果然,我找到了作者Jeroen Ooms在今年useR!研讨会的一份投影片:[Streaming Data IO in R](https://jeroenooms.github.io/mongo-slides/#1)还热腾腾的! 里面提到的`stream_in`这个函数,看起来不但是我需要的,而且还提供给R使用者以 Streaming Style处理大量JSON物件的能力。引述Jeroen Ooms投影片的内容: ```r # This doesn't work... fromJSON("hugefile.json") Error: cannot allocate vector of size 8.1 Gb ``` 在处理大量数据时,如果电脑不够力,记忆体不够,大家都常常会看到这类错误。 而Streaming Style是许多R 使用者陌生,但是在记忆体不足时非常有用的一种技巧。透 过以下的Demo(也是取自Jeroen Ooms的投影片): ```r # Calculate delay for flights over 1000 miles library(dplyr) library(curl) con <- gzcon(curl("http://jeroenooms.github.io/data/nycflights13.json.gz")) output <- file(tmp <- tempfile(), open = "wb") stream_in(con, function(df){ df <- filter(df, distance > 1000) df <- mutate(df, delta = dep_delay - arr_delay) stream_out(df, output, verbose = FALSE) }) close(output) ``` 这段程式码中,R 先透过`curl`拿到一个来自网路的`connection`,然後串接到`gzcon` 、`stream_in`、中间处理资料的逻辑,最後由`stream_out`输出到硬碟上。 其实这类connection的操作,我也是学R过後好久才知道的。不熟悉的朋友可以想像一下 ,上面的程式码就是一段不停运作的生产线。 - `curl("")`就是原料供应处,不断把未加工的资料放到生产线上。 - `gzcon`,不断的以[gzip](https://zh.wikipedia.org/zh-tw/Gzip)格式将生产线上的 资料解压缩,再放回生产线上。 - `stream_in`再不断的读取生产线上的资料,依照JSON的格式做解释,并且转换成R物件 ,放回生产线 - `function(df) { ... }`则把生产线上的R物件拿出来,做过滤,再放回生产线上 - `stream_out`则把生产线上的物件再以JSON的格式写到硬碟之中 在组装生产线的时候,除了定义各种操作之外,就是要安排顺序。而R拥有许多的 `connection`相关的函数,都是吃一个`connection`,再吐出一个`connection`。这种设 计就是要让使用者组装生产线。 ps. 在软体工程中,这是一种叫做[Decorator Pattern](https://en.wikipedia.org/wiki/Decorator_pattern)的设计模式的范例。 因此,`curl`回传一个`connection`,`gzcon`接过去处理、再来是`stream_in`... 以此 类推。用这种写法写出来的程式,不需要一次把所有资料装到记忆体之中(这就是 `fromJSON`做的事情)。在资料爆炸的现代来说,这种技巧是穷人在机器记忆体不够时, 还是能用高效率处理问题的一种方法。对於很多资工背景的朋友来说,这种技巧可能是很 基础的吧!可是对於非资工背景出身的我来说,其实也是写程式写了好多年,才注意到这 种技术。 部落格好读版:http://wush.ghost.io/r-jsonlines/ --



※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 118.161.38.94
※ 文章网址: https://webptt.com/cn.aspx?n=bbs/R_Language/M.1442323700.A.B59.html ※ 编辑: Wush978 (118.161.38.94), 09/15/2015 21:28:59
1F:推 e002311: 超赞的 09/15 21:42
2F:推 celestialgod: 推,虽然看不太懂XD 09/15 22:00
3F:推 celestialgod: 我也很苦恼为啥MATLAB没有PIPE.. 09/15 22:02
4F:→ Wush978: 看不懂吗 >_< 那我再找时间来想怎麽教connection 09/15 22:09
5F:→ celestialgod: 其实主要看不懂是为啥这样可以处理jsonlines 09/15 22:21
6F:推 naturalsmen: 意思是以後BigObject也能用R做串连了吗?? 09/16 13:02
7F:推 evilove: 大推无私心得分享 09/19 22:18







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

请输入看板名称,例如:BuyTogether站内搜寻

TOP