作者 钱亦欣

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包的功能就分享到这里,与我交流可以直接在下方留言。