Edited at

政府統計の総合窓口(e-Stat)のAPIを使ってみよう [R編]

More than 1 year has passed since last update.


はじめに

Qiita Rアドベント政府統計ポータル(e-Stat)と R でサンタさんの12月の出費動向を調べてみたという良記事がありました。

とても参考になるのですが、ポータルからマウスで項目をクリックしていくのが大変です。特に最後の方のフェーズではページが強制的にフルスクリーンになってしまい、上記アドベントの操作を確認できなくなります。

そこでAPIを使ってみます。

その前に、e-Stat API を少し触ってみましょう。


公式説明PDFをパクる

恐れおおくも総務省統計局統計センター様謹製PDF の最後の事例をパクります。

RCurl でjson形式のデータを引っ張ってきます。次世代統計システムから取得した自分のアカウントが必要です。以下のコードで yourAPPID の部分を取得したID に変更してください。

さらに加えて、統計表IDや分類表IDが必要なんですが、後述します。

> library(RCurl)

> yourAPPID <- "yourAPPID"
> url <- paste("http://api.e-stat.go.jp/rest/1.0/app/json/getStatsData?appId=",
+ yourAPPID,
+ "&statsDataId=0003013276", "&cdArea=09003,22004",
+ "&cdCat01=010920070",
+ "&cdTimeFrom=2012000101&cdTimeTo=2013000303",sep = "")
> x <- getURI(url)

あまり使ったことなかったので、この機会にjsonlite をインスコしてjsonを解釈しますた。

> library(jsonlite)

> x2 <- fromJSON(x)

構造を確認してみましょう(一部、端折ります)。

> str(x2)

List of 1
$ GET_STATS_DATA:List of 3
..$ RESULT :List of 3
..$ PARAMETER :List of 6
..$ STATISTICAL_DATA:List of 3
.. ..$ TABLE_INF:List of 9
.. .. ..$ @id : chr "0003013276"
.. .. ..$ STAT_NAME :List of 2
.. .. .. ..$ @code: chr "00200561"
.. .. .. ..$ $ : chr "家計調査"
.. .. ..$ STATISTICS_NAME: chr "家計調査 家計収支編 二人以上の世帯"
.. .. ..$ TITLE :List of 2
.. .. .. ..$ @no: chr "010"
.. .. .. ..$ $ : chr "品目分類 品目分類(平成22年改定)(総数:金額)"
.. ..$ CLASS_INF:List of 1
.. .. ..$ CLASS_OBJ:'data.frame': 5 obs. of 3 variables:
.. .. .. ..$ @id : chr [1:5] "tab" "cat01" "cat02" "area" ...
.. .. .. ..$ @name: chr [1:5] "表章項目" "品目分類(22年改定)" "世帯区分" "地域区分" ...
.. .. .. ..$ CLASS:List of 5
.. .. .. .. ..$ :List of 3
.. .. .. .. ..$ :List of 4
.. .. .. .. .. ..$ @code : chr "010920070"
.. .. .. .. .. ..$ @name : chr "ぎょうざ"
.. .. .. .. .. ..$ @level: chr "4"
.. .. .. .. .. ..$ @unit : chr "円"
.. .. .. .. ..$ :'data.frame': 4 obs. of 3 variables:
.. .. .. .. .. ..$ @code : chr [1:4] "03" "04" "01" "02"
.. .. .. .. .. ..$ @name : chr [1:4] "二人以上の世帯" "二人以上の世帯のうち勤労者世帯" "二人以上の世帯(農林漁家世帯を除く)" "二人以上の世帯のうち勤労者世帯(農林漁家世帯を除く)"
.. .. .. .. ..$ :'data.frame': 2 obs. of 3 variables:
.. .. .. .. .. ..$ @code : chr [1:2] "09003" "22004"
.. .. .. .. .. ..$ @name : chr [1:2] "09201 宇都宮市" "22130 浜松市"
.. .. .. .. .. ..$ @level: chr [1:2] "1" "1"
.. .. .. .. ..$ :'data.frame': 15 obs. of 3 variables:
.. .. .. .. .. ..$ @code : chr [1:15] "2013000303" "2013000202" "2013000101" "2012001212" ...
.. .. .. .. .. ..$ @name : chr [1:15] "2013年3月" "2013年2月" "2013年1月" "2012年12月" ...
.. ..$ DATA_INF :List of 2
.. .. ..$ NOTE :'data.frame': 3 obs. of 2 variables:
.. .. ..$ VALUE:'data.frame': 30 obs. of 7 variables:
.. .. .. ..$ @tab : chr [1:30] "01" "01" "01" "01" ...
.. .. .. ..$ @cat01: chr [1:30] "010920070" "010920070" "010920070" "010920070" ...
.. .. .. ..$ @cat02: chr [1:30] "03" "03" "03" "03" ...
.. .. .. ..$ @area : chr [1:30] "09003" "09003" "09003" "09003" ...
.. .. .. ..$ @time : chr [1:30] "2013000303" "2013000202" "2013000101" "2012001212" ...
.. .. .. ..$ @unit : chr [1:30] "円" "円" "円" "円" ...
.. .. .. ..$ $ : chr [1:30] "358" "310" "294" "464" ...

とりあずデータを取り出すには GET_STATS_DATA$STATISTICAL_DATA$DATA_INF$VALUEだけ抜けば良いことが分かりました。

抜きます。

> df <- x2$GET_STATS_DATA$STATISTICAL_DATA$DATA_INF$VALUE

列は増えていますが、最初に言及したPDFと多分同じですね。

> colnames(df)

[1] "@tab" "@cat01" "@cat02" "@area" "@time" "@unit" "$"
> colnames(df)[7] <- "@yen"
> head(df)
@tab @cat01 @cat02 @area @time @unit @yen
1 01 010920070 03 09003 2013000303 円 358
2 01 010920070 03 09003 2013000202 円 310
3 01 010920070 03 09003 2013000101 円 294
4 01 010920070 03 09003 2012001212 円 464
5 01 010920070 03 09003 2012001111 円 377
6 01 010920070 03 09003 2012001010 円 324


データのクラスIDを確認する方法

ちなみに政府統計APIを利用するには、各種カテゴリのクラス・コードIDを知る必要があります。

上で抽出したJSONフォーマットでも CLASS_INF$CLASS_OBJ$CLASS に保存されています。

> # 以下にIDが確認できます

> x2$GET_STATS_DATA$STATISTICAL_DATA$CLASS_INF$CLASS_OBJ[1:2]
@id @name
1 tab 表章項目
2 cat01 品目分類(22年改定)
3 cat02 世帯区分
4 area 地域区分
5 time 時間軸(月次)
> # ついでなので、もっと詳しくみてみましょうか
> codes <- x2$GET_STATS_DATA$STATISTICAL_DATA$CLASS_INF$CLASS_OBJ$CLASS
> length(codes)
[1] 5
> codes
[[1]]
[[1]]$`@code`
[1] "01"
[[1]]$`@name`
[1] "金額"
[[1]]$`@level`
[1] ""

[[2]]
[[2]]$`@code`
[1] "010920070"
[[2]]$`@name`
[1] "ぎょうざ"
[[2]]$`@level`
[1] "4"
[[2]]$`@unit`
[1] "円"

[[3]]
@code @name @level
1 03 二人以上の世帯 1
2 04 二人以上の世帯のうち勤労者世帯 1
3 01 二人以上の世帯(農林漁家世帯を除く) 1
4 02 二人以上の世帯のうち勤労者世帯(農林漁家世帯を除く) 1

[[4]]
@code @name @level
1 09003 09201 宇都宮市 1
2 22004 22130 浜松市 1

[[5]]
@code @name @level
1 2013000303 2013年3月 1
2 2013000202 2013年2月 1
3 2013000101 2013年1月 1
4 2012001212 2012年12月 1
5 2012001111 2012年11月 1


政府統計の統計表IDを確認する方法

さて、APIを利用して統計表を抜くには、そのIDが必要なので、取り出します。とても時間がかかります。ここはXMLなので XML パッケージを使います。

> library(XML)

> url <- paste("http://statdb.nstac.go.jp/rest/1.0/app/getStatsList?appId=", yourAPPID, sep = "")
> estat <- xmlParse(url)

Rでやるのが辛いなら、端末で抜きましょう。

$ wget http://statdb.nstac.go.jp/rest/1.0/app/getStatsList?appId=yourAPPID --output-document=estat.xml

いちど抜いたら保存しておきましょう。


「家計調査 家計収支編 二人以上の世帯」を抜く

Qiita Rアドベント記事に政府統計ポータル(e-Stat)と R でサンタさんの12月の出費動向を調べてみたではマウス操作でデータをCSVファイルとして抽出しています。

これをAPIでやってみましょう。

そのためには統計表 ID やリストIDが必要です。上で統計表ID一覧を取得済みですから、ここを検索します。

> library(XML)

> # url <- paste("http://statdb.nstac.go.jp/rest/1.0/app/getStatsList?appId=", yourAPPID, sep = "")
> # estat <- xmlParse(url)
> # あるいは保存したファイルから estat <- xmlParse("estat.xml")
> #
> # ちなみにこの操作は、オブジェクトをコピーするのではなく、もとのデータへの参照になっています
> est1 <- getNodeSet(estat, "//GET_STATS_LIST//DATALIST_INF//STATISTICS_NAME")
>
> # リスト名を取り出します(これも時間がかかります)
> tmp <- xmlSApply(est1, function(x) xmlSApply(x, xmlValue))
>
> #ちなみにtmpオブジェクトも保存しておくといいでしょう
> # save(tmp, file = "estatIdNames.rda")
> # 検索して、該当するリストの添え字を取ります
> num <- grep("家計調査 家計収支編 二人以上の世帯", tmp)
> nodes <- getNodeSet(estat, "//GET_STATS_LIST//DATALIST_INF//LIST_INF")
> nodes[num]
[[1]]
<LIST_INF id="0002070001">
<STAT_NAME code="00200561">家計調査</STAT_NAME>
<GOV_ORG code="00200">総務省</GOV_ORG>
<STATISTICS_NAME>家計調査 家計収支編 二人以上の世帯</STATISTICS_NAME>
<TITLE no="001">用途分類 用途分類(総数)</TITLE>
<CYCLE>月次</CYCLE>
<SURVEY_DATE>0</SURVEY_DATE>
<OPEN_DATE>2014-12-26</OPEN_DATE>
<SMALL_AREA>0</SMALL_AREA>
</LIST_INF>

[[2]]
<LIST_INF id="0002070002">
<STAT_NAME code="00200561">家計調査</STAT_NAME>
<GOV_ORG code="00200">総務省</GOV_ORG>
<STATISTICS_NAME>家計調査 家計収支編 二人以上の世帯</STATISTICS_NAME>
<TITLE no="001">用途分類 用途分類(総数)</TITLE>
<CYCLE>四半期</CYCLE>
<SURVEY_DATE>0</SURVEY_DATE>
<OPEN_DATE>2014-11-14</OPEN_DATE>
<SMALL_AREA>0</SMALL_AREA>
</LIST_INF>

以下、あと少し続くけど略

まあ、さらに検索しても良いのですが、疲れたので、目視で以下を確認しました。

[[22]]

<LIST_INF id="0003015188">
<STAT_NAME code="00200561">家計調査</STAT_NAME>
<GOV_ORG code="00200">総務省</GOV_ORG>
<STATISTICS_NAME>家計調査 家計収支編 二人以上の世帯</STATISTICS_NAME>
<TITLE no="010">品目分類 品目分類(平成22年改定)(総数:金額)</TITLE>
<CYCLE>四半期</CYCLE>
<SURVEY_DATE>0</SURVEY_DATE>
<OPEN_DATE>2014-11-14</OPEN_DATE>
<SMALL_AREA>0</SMALL_AREA>
</LIST_INF>

これをすっこ抜きます。ここから再び json をい使いましょう(XML で取得する方法を後述します)。これまた時間かかります。これまた時間かかります。

> url <- paste("http://api.e-stat.go.jp/rest/1.0/app/json/getStatsData?appId=",

+ yourAPPID,
+ "&statsDataId=0003015188", sep = "")
> x <- getURI(url)

構造を確認します。

> x2 <- fromJSON(x)

> x2$GET_STATS_DATA$STATISTICAL_DATA$CLASS_INF$CLASS_OBJ[1:2]
@id @name
1 tab 表章項目
2 cat01 品目分類(22年改定)
3 cat02 世帯区分
4 area 地域区分
5 time 時間軸(四半期)

ゲーム関係のIDを探します。

> num <- grep("ゲーム|がん具",x2$GET_STATS_DATA$STATISTICAL_DATA$CLASS_INF$CLASS_OBJ$CLASS[[2]][,2])

> x2$GET_STATS_DATA$STATISTICAL_DATA$CLASS_INF$CLASS_OBJ$CLASS[[2]][num,]
@code @name @level @unit
521 090203010 テレビゲーム機 3 円
522 090203150 ゲームソフト等 3 円
523 090203020 他のがん具 3 円
559 090442000 入場・観覧・ゲーム代 4 円
567 090442060 他の入場・ゲーム代 5 円
# > grep("ゲーム|がん具",x2[[1]][3]$STATISTICAL_DATA$CLASS_INF$CLASS_OBJ$CLASS, value = TRUE, perl = TRUE)
# [1] "list(`@code` = c(\"090203010\", \"090203150\", \"090203020\"), `@name` = c(\"テレビゲーム機\", \"ゲームソフト等\", \"他のがん具\"), `@level` = c(\"3\", \"3\, \"3\"), `@unit` = c(\"円\", \"円\, \"円\"))"

これらのIDをカテゴリ01 (cdCat01) に指定して、もう一回検索してみましょうか。

> url <- paste("http://api.e-stat.go.jp/rest/1.0/app/json/getStatsData?appId=",

+ yourAPPID,
+ "&statsDataId=0003015188",
+ "&cdCat01=090203010,090203150,090203020", sep = "")
> x <- getURI(url)
>
> x2 <- fromJSON(x)
> df <- x2$GET_STATS_DATA$STATISTICAL_DATA$DATA_INF$VALUE
> head(df)
@tab @cat01 @cat02 @area @time @unit $
1 01 090203010 03 00000 2014000709 円 191
2 01 090203010 03 00000 2014000406 円 144
3 01 090203010 03 00000 2014000103 円 206

多分、これで良いんでしょうか。


XML として抽出するなら

ちなみに XML を使う場合は、http://api.e-stat.go.jp/rest/1.0/app/json/getStatsData? から json の部分を削ります。

> url <- paste ("http://api.e-stat.go.jp/rest/1.0/app/getStatsData?appId=", yourAPPID, 

+ "&statsDataId=0003015188",
+ sep = "")
> library (XML)
> estatX <- xmlParse(url)
> estatTable <- getNodeSet(estatX, "//GET_STATS_DATA//STATISTICAL_DATA//CLASS_INF//CLASS_OBJ")
> # xmlRoot () xmlChildren () で辿っていってもいいです
> # estatTableの二つ目のリストは 品目分類 `cat01` ですが、何でしょうか?
> estatTable [[2]]
<CLASS_OBJ id="cat01" name="品目分類(22年改定)">
<CLASS code="000100000" name="世帯数分布(抽出率調整)" level="1" unit="一万分比"/>
<CLASS code="000200000" name="集計世帯数" level="1" unit="世帯"/>
<CLASS code="000300000" name="世帯人員" level="1" unit="人"/>
<CLASS code="000400000" name="18歳未満人員" level="2" unit="人"/>
<CLASS code="000500000" name="65歳以上人員" level="2" unit="人"/>
<CLASS code="000600000" name="65歳以上無職者人員" level="3" unit="人"/>
<CLASS code="000700000" name="有業人員" level="1" unit="人"/>
<CLASS code="000800000" name="世帯主の年齢" level="1" unit="歳"/>
<CLASS code="000900000" name="持家率" level="1" unit="%"/>
<CLASS code="001000000" name="家賃・地代を支払っている世帯の割合" level="1" unit="%"/>
<CLASS code="001100000" name="消費支出" level="1" unit="円"/>
<CLASS code="010000000" name="食料" level="1" unit="円"/>
<CLASS code="010100000" name="穀類" level="2" unit="円"/>
<CLASS code="010110001" name="米" level="3" unit="円"/>
中略
> # 長いので簡略化します
> xmlAttrs(estatTable[[2]],"id")
id name
"cat01" "品目分類(22年改定)"
> # "cat01" は品目なので、ゲームと玩具のIDを確認します
> estatClass <- getNodeSet(estatX, "//GET_STATS_DATA//STATISTICAL_DATA//CLASS_INF//CLASS_OBJ//CLASS")
>
> tmp1 <- sapply(estatClass,xmlGetAttr, "name")
>
> num <- grep("ゲーム|がん具", tmp1)
>
> # 検索時にゲームなどの品目を利用したい時はこのIDを使います
> # tmp2 <- sapply(estatClass,xmlGetAttr, "code")
> (games <- data.frame(code = tmp1[num], name = tmp1 [num]))
code name
1 090203010 テレビゲーム機
2 090203150 ゲームソフト等
3 090203020 他のがん具
4 090442000 入場・観覧・ゲーム代
5 090442060 他の入場・ゲーム代

> ## IDが確認できたので、これを使って検索しなおしてみましょう
> url2 <- paste ("http://api.e-stat.go.jp/rest/1.0/app/getStatsData?appId=", yourAPPID,
+ "&statsDataId=0003015188",
+ "&cdCat01=090203010,090203150,090203020",
+ sep = "")
>
> estatX2 <- xmlParse(url2)
> estatData2 <- getNodeSet(estatX2, "//GET_STATS_DATA//STATISTICAL_DATA//DATA_INF//VALUE")
> df <- do.call ("rbind", lapply (estatData2, xmlAttrs))
> value <- lapply(estatData2,xmlValue)
> df <- cbind(df,value)
> df <- as.data.frame(df)
> head(df)
tab cat01 cat02 area time unit value
1 01 090203010 03 00000 2014000709 円 191
2 01 090203010 03 00000 2014000406 円 144
3 01 090203010 03 00000 2014000103 円 206
4 01 090203010 03 00000 2013001012 円 526
5 01 090203010 03 00000 2013000709 円 172
6 01 090203010 03 00000 2013000406 円 164


補足

Rでe-Statを利用する方法としてとRで統計API というサイトがあります。以上の操作はベタなので、みなさん、このRで統計API で公開されている関数を利用しましょうね。

また、政府統計の総合窓口(e-Stat)ーAPI機能テストフォームなんかも使いましょう。