左手用R右手Python系列之——json序列化與反序列化

json格式數據作為如今越來越流行的數據交換格式,幾乎已經成為web端數據交互的標準,主流的數據科學語言R,Python都中都有非常完善的半結構化數據與json數據進行通訊。本篇文章將會通過簡單案例介紹R語言與Python中與json數據進行序列化與反序列化的常用函數。

json的數據以鍵值對形式存在,在R語言中,符合此標準的就是基礎數據對象中的list(嚴格來說,R語言中所有數據對象都可以表示為list,但是可以保存遞歸結構只有list一種)。

在R語言中,涉及到json數據處理的,主要是list轉換為json和json轉換為普通的list。前者被稱為序列化,後者被稱為反序列化。(也可以理解為編碼或者解碼的過程)雖然R語言中有三個包可以處理json序列化與反序列化過程(rjson、RJSONIO、jsonlite),但是實際應用最多,功能相對完善的,要數最後一個jsonlite包,這裡僅以jsonlite包為例進行講解。

library("jsonlite")nlibrary("magrittr")nlibrary("RCurl")nmylist <- list(n "name"="Raiders of the Lost Ark",n "year"=1981,n "actors"=list(n "Indiana Jones" = "Harrison Ford",n "Dr. Ren Belloq"= "Paul Freeman" n ),n "producers"= c("Frank Marshall", "George Lucas", "Howard Kazanjian"),n "budget" = 18000000,n "academy_award_ve"= TRUEn )n

jsonlite包中的toJSON函數負責將R語言中的數據對象(主要是list)進行序列化。序列化之前需要聲明一點,llist必須提供命名,因為json需要嚴格的鍵值對結構。

toJSON函數有兩個需要強調的參數。

第一個是auto_unbox參數,這個參數控制json對象中值(value)在長度為1時,是否強制轉換為數組。如果value對象長度唯一,通常不需要數組化,(因為R語言中沒有標量,長度為一的字元或者數值都是原子型向量,默認也會被轉換為數組【長度為1】)在大多數場合下,需要指定參數auto_unbox為TRUE。

auto_unbox參數默認為FALSE時:

toJSON(mylist)n{"name":["Raiders of the Lost Ark"],"year":[1981],"actors":{"Indiana Jones":["Harrison Ford"],"Dr. Ren Belloq":["Paul Freeman"]},"producers":["Frank Marshall","George Lucas","Howard Kazanjian"],"budget":[18000000],"academy_award_ve":[true]}n

auto_unbox參數指定為TRUE時:

toJSON(mylist,auto_unbox = TRUE)n{"name":"Raiders of the Lost Ark","year":1981,"actors":{"Indiana Jones":"Harrison Ford","Dr. Ren Belloq":"Paul Freeman"},"producers":["Frank Marshall","George Lucas","Howard Kazanjian"],"budget":18000000,"academy_award_ve":true}n

prettty參數用於控制輸出格式是否進行排版美化(換行渲染)

toJSON(mylist,auto_unbox = TRUE,pretty = TRUE)n {n "name" : "Raiders of the Lost Ark",n "year" : 1981,n "actors" : {n "Indiana Jones": "Harrison Ford", n "Dr. Ren Belloq": "Paul Freeman" n },n "producers": ["Frank Marshall", "George Lucas", "Howard Kazanjian"],n "budget" : 18000000,n "academy_award_ve": truen }n

但是pretty參數僅僅是一個美化參數,僅僅為了更好地進行可視化輸出,對於json內容並沒有任何影響,在使用時(特別是WEB上傳json參數時,通常沒有必要設置)。

反序列化:

這裡的反序列化就是指如何將一組json字元串反序列化為R語言中的list結構,這種需求在網路數據抓取中使用的及其頻繁。

第一種情況:當json字元串來自於手動創建的字元串時:

myjson <- {"name":"Raiders of the Lost Ark","year":1981,"actors":{"Indiana Jones":"Harrison Ford","Dr. Ren Belloq":"Paul Freeman"},"producers":["Frank Marshall","George Lucas","Howard Kazanjian"],"budget":18000000,"academy_award_ve":true}nfromJSON(myjson)n$namen[1] "Raiders of the Lost Ark"n$yearn[1] 1981n$actorsn$actors$`Indiana Jones`n[1] "Harrison Ford"n$actors$`Dr. Ren Belloq`n[1] "Paul Freeman"n$producersn[1] "Frank Marshall" "George Lucas" "Howard Kazanjian"nn$budgetn[1] 18000000nn$academy_award_ven[1] TRUEn

因為json字元串中規定使用英文雙引號來包裹所有key鍵名和字元串格式的value值,所有自己手動建立的包含有json字元串向量時,要使用英文單引號進行表示。這樣不至於引起R語言中符號邏輯的混亂。

如果非要使用雙引號來建立時,則必須在json字元串內部的所有雙引號前使用「」進行轉義,否則R語言無法識別。

myjson <- "{"name":"Raiders of the Lost Ark","year":1981,"actors":{"Indiana Jones":"Harrison Ford","Dr. Ren Belloq":"Paul Freeman"},"producers":["Frank Marshall","George Lucas","Howard Kazanjian"],"budget":18000000,"academy_award_ve":true}"nfromJSON(myjson)n$namen[1] "Raiders of the Lost Ark"n$yearn[1] 1981nn$actors$actorsn$`Indiana Jones`n[1] "Harrison Ford"nn$actors$`Dr. Ren Belloq`n[1] "Paul Freeman"nn$producersn[1] "Frank Marshall" "George Lucas" "Howard Kazanjian"nn$budgetn[1] 18000000nn$academy_award_ven[1] TRUEn

如果看過之前的幾篇關於web抓取的文章,你已經好奇為啥web返回的json原始字元串向量裡面存在大量的「」和「rn」。

url <- "http://www.r-datacollection.com/materials/ch-3-xml/peanuts.json"ngetURL(url)n "[rn {rn "name":"van Pelt, Lucy",rn "sex":"female",rn "age":32rn },rn {rn "name":"Peppermint, Patty",rn "sex":"female",rn "age":nullrn },rn {rn "name":"Brown, Charlie",rn "sex":"male",rn "age":27rn }rn]"ngetURL(url) %>% cat()nn[n { "name":"van Pelt, Lucy", "sex":"female", "age":32n },n { "name":"Peppermint, Patty", "sex":"female", "age":nulln },n { "name":"Brown, Charlie", "sex":"male", "age":27n }n]n

實際上這裡很好解釋,從web端返回的json數據內部所有的分隔符都是雙引號,而反會的整個json字串整體作為一個長度為1的原子型字元串向量,但是在R語言中,字元串向量默認使用雙引號進行分割,這樣就導致json內層的雙引號與外側字元串向量的分割符出現衝突,如果不做任何更改,這樣的格式是R語言無法識別的。

fromJSON("{"name":"duyu"}")nError: unexpected symbol in "fromJSON("{"name"nnfromJSON("{"name":"duyu"}")n$namen[1] "duyu"n

所以R語言自動給內層的json分隔符【也就是內層的所有雙引號全部都加了轉義符,至於」rn」,那僅僅是一個換行符,用於優化json排版,使用cat函數可以渲染出最終的效果】。這才是在R語言中,json返回值中出現大量反斜杠的原因。

Python:

Python中主要使用json包進行json的序列化與反序列化。

json序列化:

import jsonnmydict = {n "name":"Raiders of the Lost Ark",n "year":1981,n "actors":{n "Indiana Jones" :"Harrison Ford",n "Dr. Ren Belloq": "Paul Freeman" n },n "producers": ["Frank Marshall", "George Lucas", "Howard Kazanjian"],n "budget" : 18000000,n "academy_award_ve": Truen }njson.dumps(mydict)n{"name": "Raiders of the Lost Ark", "year": 1981, "actors": {"Indiana Jones": "Harrison Ford", "Dr. Ren Belloq": "Paul Freeman"}, "producers": ["Frank Marshall", "George Lucas", "Howard Kazanjian"], "budget": 18000000, "academy_award_ve": true}n

序列化的場景主要用在web請求,如果要求參數提交以json格式提交的話,就需要序列化之後進行提交。(仔細觀察你會發現json的數據格式與Python中的dict出奇的一致,確實挺像,但是很多細節明顯不一樣,比如布爾值,py中是True,json中是true)

反序列化同樣涉及到自建json字元串。與R語言中情形一樣,使用英文單引號作為字元串分隔符,內層的json字元串對象則必須使用雙引號作為分割符號。這樣不會導致內外層符號混亂。

myjson = {"name": "Raiders of the Lost Ark", "year": 1981, "actors": {"Indiana Jones": "Harrison Ford", "Dr. Ren Belloq": "Paul Freeman"}, "producers": ["Frank Marshall", "George Lucas", "Howard Kazanjian"], "budget": 18000000, "academy_award_ve": true}njson.loads(myjson)n{academy_award_ve: True, actors: {Dr. Ren Belloq: Paul Freeman, Indiana Jones: Harrison Ford}, budget: 18000000, name: Raiders of the Lost Ark, producers: [Frank Marshall, George Lucas, Howard Kazanjian], year: 1981}n

但是你如果再建立字元串時,堅持使用雙引號作為分隔符,為了防止符號混亂,同樣需要使用右斜杠轉義。

myjson = "{"name": "Raiders of the Lost Ark", "year": 1981, "actors": {"Indiana Jones": "Harrison Ford", "Dr. Ren Belloq": "Paul Freeman"}, "producers": ["Frank Marshall", "George Lucas", "Howard Kazanjian"], "budget": 18000000, "academy_award_ve": true}"njson.loads(myjson)n{academy_award_ve: True, actors: {Dr. Ren Belloq: Paul Freeman, Indiana Jones: Harrison Ford}, budget: 18000000, name: Raiders of the Lost Ark, producers: [Frank Marshall, George Lucas, Howard Kazanjian], year: 1981}n

json數據通常來源於webd端的數據請求返回值,但是在Python中,返回值的原始向量,並不會出現像R語言中那種裡面存在大量反斜杠的情況,原因在於,Python的字元串分割符默認使用英文單引號(R語言中默認使用英文雙引號)。而web端返回的json值嚴格規定使用英文雙引號作為分隔符,這樣內層是雙引號,外層默認是單引號,所以不會引起歧義,不需要使用反斜杠進行轉義。

import requestsnurl = "http://www.r-datacollection.com/materials/ch-3-xml/peanuts.json"requests.get(url).text[rn {rn "name":"van Pelt, Lucy",rn "sex":"female",rn "age":32rn },rn {rn "name":"Peppermint, Patty",rn "sex":"female",rn "age":nullrn },rn {rn "name":"Brown, Charlie",rn "sex":"male",rn "age":27rn }rn]n

可以看到返回值僅僅是包含有rn這種換行符(用於美化json排版)。

好在requests函數有一個默認的json方法用於直接處理json返回值。

requests.get(url).json()n[{age: 32, name: van Pelt, Lucy, sex: female}, {age: None, name: Peppermint, Patty, sex: female}, {age: 27, name: Brown, Charlie, sex: male}]n

以上json方法調用直接回直接將json字元串轉換為Python中的內建對象,dict,但是如果使用urllib包請求,可能就需要使用json庫中的json.loads()函數進行反序列化了。

json.loads(requests.get(url).text)n[{age: 32, name: van Pelt, Lucy, sex: female}, {age: None, name: Peppermint, Patty, sex: female}, {age: 27, name: Brown, Charlie, sex: male}]n

以上便是R語言與Python中內建非結構化數據對象(list、dict)與json之間的轉化方法與核心要點及注意事項。這些函數一定要牢記,在遇到非結構化數據處理時經常用到。

在線課程請點擊文末原文鏈接:

Hellobi Live | 9月12日 R語言可視化在商務場景中的應用R

往期案例數據請移步本人GitHub:

github.com/ljtyduyu/Dat


推薦閱讀:

關於Excel表格如何處理|一點心得
怎麼樣才算是精通 Python?
三峽發電量估算系統在葛洲壩中的應用可行性分析
python與numpy使用的一些小tips(1)
小說人物關係的可視化

TAG:Python | R编程语言 | JSON |