R語言轉換並儲存json檔案--使用jsonlite包

錢亦欣發表於2017-07-03

作者 錢亦欣

json是當下非常流行的資料交換格式,有著簡單易用,易讀(人和機器都容易)等特點。目前挺流行的非關係型資料庫MongoDB就可以簡單理解為一個json的容器,同時mysql(5.7以上版本),postgresql等關係型資料庫也開始支援這一資料結構。因此,掌握關於json的一些知識很有必要,你可以訪問它的官網來了解它的結構和在各種程式語言中的相應的庫。

當然,身為一個統計專業的學生,我們接觸到的資料很多時候還是結構化的DataFrame格式,如果你想把這一格式的儲存轉換為json格式,我在這裡給大家推薦一個很好用的包--jsonlite。

jsonlite是專門用來轉換,讀取和儲存json檔案的R包,按照作者的描述,它提供了json和R中常用資料型別的雙向轉換功能,高效、簡潔而且穩定。根據我的使用體驗,也確實如此。閒言少敘,讓我們進入正題。

1. 讀取json檔案

json檔案的讀取可以用read_json()函式實現,這個函式的第二個引數 simplifyVector 如果設定為TRUE,則json結構會被簡化為向量,FALSE則會變為列表

2. json結構和R中原生資料結構的相互轉換

(1)jsonlite包中的fromJSON函式就是把json結構的資料轉換為R中常見資料型別的工具。與之相反,toJSON函式則是把R中原生的資料結構轉變為json。具體的引數設定和二者的結構對應關係如下: enter image description here

​我們來展開港一港:

  • Atomic Vectors

如果你的JSON結構本身就是一個簡單的陣列,那麼用simplifyVector引數就能把它直接轉換為向量

# JSON 簡單陣列
json <- '["Mario", "Peach", null, "Bowser"]'
# 轉換為向量
fromJSON(json)

[1] "Mario"  "Peach"  NA  "Bowser"

如果把這個引數設定為false,那麼就會轉換為list。

fromJSON(json, simplifyVector = FALSE)

[[1]]
[1] "Mario"
[[2]]
[1] "Peach"
[[3]]
NULL
[[4]]
[1] "Bowser"
  • Data Frame

如果引數為simplifyDataFrame,那麼包含物件的JSON陣列(key-value pairs)會轉化為資料框

json <-
'[
  {"Name" : "Mario", "Age" : 32, "Occupation" : "Plumber"}, 
  {"Name" : "Peach", "Age" : 21, "Occupation" : "Princess"},
  {},
  {"Name" : "Bowser", "Occupation" : "Koopa"}
]'
mydf <- fromJSON(json)
mydf

 Name Age Occupation
1  Mario  32    Plumber
2  Peach  21   Princess
3   <NA>  NA       <NA>
4 Bowser  NA      Koopa

資料框轉換JSON只要使用toJSON函式就行(空格和換行符在JSON裡可以省略)

mydf$Ranking <- c(3, 1, 2, 4)
toJSON(mydf, pretty=TRUE) # pretty 引數能新增一些空格和換行符是的輸出的json更美觀

[
  {
  "Name": "Mario",
  "Age": 32,
  "Occupation": "Plumber",
  "Ranking": 3
  },
  {
  "Name": "Peach",
  "Age": 21,
  "Occupation": "Princess",
  "Ranking": 1
  },
  {
  "Ranking": 2
  },
  {
  "Name": "Bowser",
  "Occupation": "Koopa",
  "Ranking": 4
  }
] 
  • Matrices and Arrays

simplifyMatrix 引數被使用, 包含登場或者子陣列的JSON陣列就會變轉化為矩陣或者更高階的R陣列:

json <- '[
  [1, 2, 3, 4],
  [5, 6, 7, 8],
  [9, 10, 11, 12]
]'
mymatrix <- fromJSON(json)
mymatrix

     [,1] [,2] [,3] [,4]
[1,]    1    2    3    4
[2,]    5    6    7    8
[3,]    9   10   11   12

同樣地, toJSON()函式可以逆向實現上述過程:

toJSON(mymatrix, pretty = TRUE)

[
  [1, 2, 3, 4],
  [5, 6, 7, 8],
  [9, 10, 11, 12]
] 

只要陣列的維數對應,就能很容易的把json簡化為R中的多維陣列

json <- '[
   [[1, 2], 
    [3, 4]],
   [[5, 6], 
    [7, 8]],
   [[9, 10],
    [11, 12]]
]'
myarray <- fromJSON(json)
myarray[1, , ]

     [,1] [,2]
[1,]    1    2
[2,]    3    4
myarray[ , ,1]
     [,1] [,2]
[1,]    1    3
[2,]    5    7
[3,]    9   11

3. 修改json

其實R中的json只是包含了特殊屬性的字串而已,利用stringr包中的字元操作函式就能對json進行修改。

# 構建json物件的過程其實就暴露了它是字串的實質
json <- 
'[
  {"Name" : "Mario", "Age" : 32, "Occupation" : "Plumber"},
  {"Name" : "Peach", "Age" : 21, "Occupation" : "Princess"}
]'
mydf <- fromJSON(json)
mydf$Ranking <- c(3, 1)
json = toJSON(mydf, pretty = TRUE)
json

[
  {
  "Name": "Mario",
  "Age": 32,
  "Occupation": "Plumber",
  "Ranking": 3
  },
  {
  "Name": "Peach",
  "Age": 21,
  "Occupation": "Princess",
  "Ranking": 1
  }
]

# 檢視json物件的型別和儲存模式
class(json)
[1] "json"
mode(json)
[1] "character"

# 將json物件中的'Ranking'全部替換為'Rank'
library(stringr)
cat(str_replace_all(json, 'Ranking', 'Rank'))

[
  {
  "Name": "Mario",
  "Age": 32,
  "Occupation": "Plumber",
  "Rank": 3
  },
  {
  "Name": "Peach",
  "Age": 21,
  "Occupation": "Princess",
  "Rank": 1
  }
]

# 修改原有的json結構
cat(str_c("{\'newkey\': \'newvalue\',\n \'oldlist\': ",json,'}'))

{'newkey': 'newvalue',
 'oldlist': [
  {
  "Name": "Mario",
  "Age": 32,
  "Occupation": "Plumber",
  "Ranking": 3
  },
  {
  "Name": "Peach",
  "Age": 21,
  "Occupation": "Princess",
  "Ranking": 1
  }
]}

我知道這個方法可能看起來有些怪,但他能達到我們的目的。

4. 儲存json檔案到本地

如果你使用這個包提供的write_json()函式,那麼你儲存的檔案會包含大量的轉義符''\'',而且換行縮排什麼的也會以"\n"的符號形式儲存。

str(json)

Class 'json'  chr "[\n  {\n    \"Name\": \"Mario\",\n    \"Age\": 32,\n    \"Occupation\": \"Plumber\",\n
\"Ranking\": 3\n  },..."| __truncated__

最終包括在檔案裡的就是這個包含了換行符和轉義字元的檔案。如果你希望以上面列印出的友好格式來儲存json,可以用如下方法

cat(json, file = 'json.txt', fill = FALSE, labels = NULL, append = FALSE)

cat()函式和dos命令一樣,既可以在螢幕上列印檔案,也可以儲存。當然建立一個connection也可以,這就類似於python裡open一個txt,再逐行寫入,最後close了。

cat(json, file = (con <- file('json.txt', "w", encoding = "UTF-8")))
close(con)

結語

關於R中jsonlite包的功能就分享到這裡,與我交流可以直接在下方留言。

相關文章