e-Stat APIがちょっとバージョンアップしていて、統計データ取得APIのデータ形式にCSVが追加されました。
前にRからe-Stat APIを使ったときはちょっとJSONをdata.frameに直すのが大変すぎて、
estatapiというパッケージをつくったんですが、
…ひょっとしてもうパッケージいらない?と思ったので試してみました。
変更点
JSON形式のパスはこうでした。
http://api.e-stat.go.jp/rest/<バージョン>/app/json/getStatsData?<パラメータ群>
CSV形式のはこうなります。2.1以降でしか使えないので今のところ<バージョン>
には2.1一択です。
http://api.e-stat.go.jp/rest/<バージョン>/app/getSimpleStatsData?<パラメータ群>
参考:政府統計の総合窓口(e-Stat)のAPI 仕様 2.1版 | 政府統計の総合窓口(e-Stat)−API機能
バージョン2.1をRから使ってみる
使ってみます。
library(httr) appId <- "XXXXXXXX" res_data <- GET( "http://api.e-stat.go.jp/", path = "rest/2.1/app/getSimpleStatsData", query = list( appId = appId, statsDataId = "0003103532", cdCat01 = "010800130,010800140" )) res <- content(res_data)
あっさり取れました。
が、なんかこのres
を表示しようとするとRのコンソールが固まります。あれ? データがでかすぎる?とか思って、
head(res)
とやっても同じく固まります。むうう…
何かがおかしい
元のレスポンスのContent-Type
ヘッダを見てみます。
res_data$headers$`content-type` #> [1] "text/plain;charset=utf-8"
あれ、これがtext/csv
とかになってないせい?とか思ったんですが、むりやりread_csv()
してみてもなんか様子が変です。
res_csv <- readr::read_csv(res) #> Warning: 13097 parsing failures. #> row col expected actual #> 1 -- 1 columns 2 columns #> 2 -- 1 columns 2 columns #> 3 -- 1 columns 2 columns #> 5 -- 1 columns 2 columns #> 6 -- 1 columns 2 columns #> ... ... ......... ......... #> .See problems(...) for more details. dim(res_csv) #> [1] 13099 1 head(res_csv) #> # A tibble: 6 x 1 #> RESULT #> <chr> #> 1 STATUS #> 2 ERROR_MSG #> 3 DATE #> 4 RESULT_INF #> 5 TOTAL_NUMBER #> 6 FROM_NUMBER
おかしい。と思って生データを見てみると…
library(stringr) cat(str_sub(res, 0, 1000)) #> "RESULT" #> "STATUS","0" #> "ERROR_MSG","正常に終了しました。" #> "DATE","2016-07-16T23:14:46.597+09:00" #> "RESULT_INF" #> "TOTAL_NUMBER","13072" #> "FROM_NUMBER","1" #> "TO_NUMBER","13072" #> "TABLE_INF","0003103532" #> "STAT_NAME","00200561","家計調査" #> "GOV_ORG","00200","総務省" #> "STATISTICS_NAME","家計調査 家計収支編 二人以上の世帯" #> "TITLE","010","品目分類 品目分類(平成27年改定)(総数:金額)" #> "CYCLE","月次" #> "SURVEY_DATE","0" #> "OPEN_DATE","2016-07-01" #> "SMALL_AREA","0" #> "MAIN_CATEGORY","07","企業・家計・経済" #> "SUB_CATEGORY","04","家計" #> "OVERALL_TOTAL_NUMBER","4498164" #> "UPDATED_DATE","2016-06-29" #> "STATISTICS_NAME_SPEC","家計調査","家計収支編","二人以上の世帯","","","" #> "TITLE_SPEC","品目分類","品目分類(平成27年改定)(総数:金額)","","","" #> "NOTE","***","調査又は集計していないもの" #> "NOTE","-","該当数字がないもの" #> "NOTE","X","数値が秘匿されているもの" #> "VALUE" #> "tab_code","表章項目","cat01_code","品目分類(27年改定)","cat02_code","世帯区分","area_code","地域区分","time_code","時間軸(月次)","unit","value" #> "01","金額","010800130","352 チョコレート","03","二人以上の世帯(2000年~)","00000","全国","2016000505","2016年5月","円","346" #> "01","金額","010800130","352 チョコレート","03","二人以上の世帯(2000年~)","00000","全国
グワー!!!
この書き方から察するに、フィールド数がひとつの行は見出しとして使われているようです。メタデータをどこに書くんだろう?とは思ってたんですが、この発想はなかったです。これをCSVと呼んでいいんだろうか...
がんばって読む
こうなれば取りうる戦略はひとつ。"VALUE"
までの行を無視することです。readr::read_csv()
のskip
引数を指定するのも手ですが、"VALUE"
が何行目なのかを調べるのがめんどくさそうです。
そこで、stringr::str_replace()
を使います。先頭から"VALUE"
までを空白と置換することで不要な部分を取り除きます。
改行をまたいでマッチさせるには、検索文字列をregex(..., dotall = TRUE)
でラップして指定します。あと"VALUE"
までだと改行が残ってしまうので"VALUE"\n
まで指定する点にも注意です。
library(dplyr) readr::read_csv( str_replace( res, regex('^.*"VALUE"\n', dotall = TRUE), '' ) ) #> # A tibble: 13,072 x 12 #> tab_code 表章項目 cat01_code 品目分類(27年改定) cat02_code 世帯区分 area_code 地域区分 time_code 時間軸(月次) unit value #> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <int> <chr> <chr> <dbl> #> 1 01 金額 010800130 352 チョコレート 03 二人以上の世帯(2000年~) 00000 全国 2016000505 2016年5月 円 346 #> 2 01 金額 010800130 352 チョコレート 03 二人以上の世帯(2000年~) 00000 全国 2016000404 2016年4月 円 403 #> 3 01 金額 010800130 352 チョコレート 03 二人以上の世帯(2000年~) 00000 全国 2016000303 2016年3月 円 580 #> 4 01 金額 010800130 352 チョコレート 03 二人以上の世帯(2000年~) 00000 全国 2016000202 2016年2月 円 1376 #> 5 01 金額 010800130 352 チョコレート 03 二人以上の世帯(2000年~) 00000 全国 2016000101 2016年1月 円 665 #> 6 01 金額 010800130 352 チョコレート 03 二人以上の世帯(2000年~) 00000 全国 2015001212 2015年12月 円 585 #> 7 01 金額 010800130 352 チョコレート 03 二人以上の世帯(2000年~) 00000 全国 2015001111 2015年11月 円 451 #> 8 01 金額 010800130 352 チョコレート 03 二人以上の世帯(2000年~) 00000 全国 2015001010 2015年10月 円 413 #> 9 01 金額 010800130 352 チョコレート 03 二人以上の世帯(2000年~) 00000 全国 2015000909 2015年9月 円 326 #> 10 01 金額 010800130 352 チョコレート 03 二人以上の世帯(2000年~) 00000 全国 2015000808 2015年8月 円 212 #> # ... with 13,062 more rows
何とか読めました。しかしまあ、メタデータの紐付けを自分でやらなくていいのは楽ですね。
感想
メタデータの紐付けを考えなくていいのでestatapiパッケージは内部的にはCSVを使うと思いますが、普通の人に勧められるかというと微妙ですね。。 CSVが使える!と油断して飛びつくと痛い目に遭います。備えよう。
追記(2016/07/27):
APIの仕様を見ていると、sectionHeaderFlg
というパラメータがありました。これに2
を指定すると、問題のメタデータ的な部分の出力が抑えられます。
res_data <- GET( "http://api.e-stat.go.jp/", path = "rest/2.1/app/getSimpleStatsData", query = list( appId = appId, statsDataId = "0003103532", cdCat01 = "010800130,010800140", sectionHeaderFlg = 2 )) cat(str_sub(content(res_data, as = "text"), 0, 100)) #> "VALUE" #> "tab_code","表章項目","cat01_code","品目分類(27年改定)","cat02_code","世帯区分","area_code","地域区分","time_co
とはいえ"VALUE"
だけは残るんですけど、行数が変わらなければread_csv()
のskip
が使えます。ちょっとだけ楽になりました。
readr::read_csv(content(res_data, as = "text"), skip = 1) #> # A tibble: 13,072 x 12 #> tab_code 表章項目 cat01_code 品目分類(27年改定) cat02_code 世帯区分 area_code #> <chr> <chr> <chr> <chr> <chr> <chr> <chr> #> 1 01 金額 010800130 352 チョコレート 03 二人以上の世帯(2000年~) 00000 #> 2 01 金額 010800130 352 チョコレート 03 二人以上の世帯(2000年~) 00000 #> 3 01 金額 010800130 352 チョコレート 03 二人以上の世帯(2000年~) 00000 #> 4 01 金額 010800130 352 チョコレート 03 二人以上の世帯(2000年~) 00000 #> 5 01 金額 010800130 352 チョコレート 03 二人以上の世帯(2000年~) 00000 #> 6 01 金額 010800130 352 チョコレート 03 二人以上の世帯(2000年~) 00000 #> 7 01 金額 010800130 352 チョコレート 03 二人以上の世帯(2000年~) 00000 #> 8 01 金額 010800130 352 チョコレート 03 二人以上の世帯(2000年~) 00000 #> 9 01 金額 010800130 352 チョコレート 03 二人以上の世帯(2000年~) 00000 #> 10 01 金額 010800130 352 チョコレート 03 二人以上の世帯(2000年~) 00000 #> # ... with 13,062 more rows, and 5 more variables: 地域区分 <chr>, time_code <int>, 時間軸(月次) <chr>, #> # unit <chr>, value <dbl>