jsonlite 1.2で、read_json()
とwrite_json()
という関数が追加されました。
ディスクから直接読み書きするから速い、らしい。そんなパフォーマンスを気にするほどでかいJSONファイルを扱ったことないけどいちおうメモ。
使い方
書き出し
上のブログ記事であったように、iris
をファイルを書き出してみます(iris
はdata.frameですが、listでもあります)。write_json()
を使います。
library(jsonlite) tmp <- tempfile() write_json(iris, tmp)
このファイルの中身はどうなっているでしょう。ファイルの中身を見るにはreadrパッケージのread_file()
とかread_lines()
あたりが便利です。
readr::read_file(tmp) #> [1] "[{\"Sepal.Length\":5.1,\"Sepal.Width\":3.5,\"Petal.Length\":1.4,\"Petal.Width\":0.2,\"Species\":\"setosa\"},... <truncated>
なんかJSONっぽい感じになっていますね。(わかりにくいですが、ダブルクオートが\
でエスケープされているのは、Rがprintするときに一番外側を"
で囲っているためです)
write_json()
やread_json()
は、追加の引数を指定すると、それぞれ内部で使われているtoJSON()
、fromJSON()
に渡されます。たとえば、pretty = TRUE
を指定すると、整形されたJSONになります。
write_json(iris, tmp, pretty = FALSE) cat(readr::read_lines(tmp, n_max = 10L), sep = "\n") #> [ #> { #> "Sepal.Length": 5.1, #> "Sepal.Width": 3.5, #> "Petal.Length": 1.4, #> "Petal.Width": 0.2, #> "Species": "setosa" #> }, #> { #> "Sepal.Length": 4.9,
読み込み
read_json()
を使います。
str(read_json(tmp)) #> List of 150 #> $ :List of 5 #> ..$ Sepal.Length: num 5.1 #> ..$ Sepal.Width : num 3.5 #> ..$ Petal.Length: num 1.4 #> ..$ Petal.Width : num 0.2 #> ..$ Species : chr "setosa" #> $ :List of 5 #> ..$ Sepal.Length: num 4.9 #> ..$ Sepal.Width : int 3 #> ..$ Petal.Length: num 1.4 #> ..$ Petal.Width : num 0.2 #> ..$ Species : chr "setosa" #> #> ...snip...
冒頭のrOpenSciの記事にあったように、ここはfromJSON()
と挙動が違い、デフォルトではsimplifyされません。simplifyVector = TRUE
を明示的に指定するとsimplifyされます。
str(read_json(tmp, simplifyVector = TRUE)) #> 'data.frame': 150 obs. of 5 variables: #> $ Sepal.Length: num 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ... #> $ Sepal.Width : num 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ... #> $ Petal.Length: num 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ... #> $ Petal.Width : num 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ... #> $ Species : chr "setosa" "setosa" "setosa" "setosa" ...
なぜfromJSON()
と挙動が違うのか
なんで挙動変えたんだろう...と思ってissueを見ると、data.frameに変換するときは、なるべく暗黙に変換するのではなくreadrパッケージでやってるみたいに型を指定したい、という要望があって、
OK so I guess jsonlite should only do the parsing, and than you can do the simplification, coercion, tidyfication and transformations in another package. (https://github.com/jeroenooms/jsonlite/issues/161#issuecomment-268513054)
ということでjsonliteでは余計な変換はしない、という話になったらしいです。まあこれはこれで理解できる気がする。