Python pandas で e-Stat のデータを取得したい
e-Stat とは
"「政府統計の総合窓口(e-Stat)」は、各府省が公表する統計データを一つにまとめ、統計データの検索をはじめとした、さまざまな機能を備えた政府統計のポータルサイト" だそうだ。このデータを pandas
で読めるとうれしい...ということで対応した。
インストール
$ pip install japandas
パッケージのインポート
import numpy as np np.__version__ # '1.10.2' import pandas as pd pd.__version__ # u'0.17.1' import japandas as jpd jpd.__version__ # '0.2.0'
アプリケーション ID の取得
e-Stat を利用するには 利用登録とアプリケーション ID の取得が必要。利用ガイドに沿って登録する。
データの取得
japandas
を利用してデータを取得する。データの取得は以下 2 ステップで行う
- "政府統計コード" を利用して、統計調査に含まれる統計表 ( 実データ ) の一覧とその ID ( 統計表 ID ) を取得する。
- 取得した統計表 ID を利用して、実データを取得する
1. 統計表一覧の取得
e-Stat 提供データ一覧 に含まれる統計調査のうち、今回は 00200564 全国消費実態調査 を利用する。
jpd.DataReader
で ID "00200564"
のデータを取得すると、以下のような DataFrame
が返ってくる。各カラムの詳細は e-Stat API 仕様 に記載されている。
key = "Your application ID" dlist = jpd.DataReader("00200564", 'estat', appid=key) dlist
一つの "統計表題名及び表番号" は "調査年月" が異なる複数のデータを持つことがある。値をユニークにした方が中身を確認しやすい。
tables = dlist[u'統計表題名及び表番号'].value_counts().to_frame()
tables
ここでは "平成26年全国消費実態調査 > 全国 > 品目及び購入先・購入地域に関する結果 > 単身世帯" の "男女,年齢階級,購入形態,品目別1世帯当たり1か月間の支出" のデータを取得したい。
この時点では 正確な "統計表題名及び表番号" がわからないため、まずはそれらしい文字列でレコードを抽出する。
indexer = tables.index.str.contains(u'男女,年齢階級,購入形態,品目別1世帯当たり1か月間の支出') indexer # array([False, False, False, ..., False, False, False], dtype=bool) tables[indexer]
上の結果から 正確な "統計表題名及び表番号" が得られるため、元データから対象のレコードが抽出できる。
table = tables[indexer].index[0] table # [単身世帯]フロー編第149表 男女,年齢階級,購入形態,品目別1世帯当たり1か月間の支出 target = dlist[dlist[u'統計表題名及び表番号'] == table] target
2. 実データの取得
- で調べた "統計表 ID" (
"0003109612"
) をjpd.DataReader
に渡せばよい。
df = jpd.DataReader("0003109612", 'estat', appid=key) # 略
が、いちいち文字列を抽出したり再入力するのは面倒だ。そんな時は、上の結果 ( 取得対象の "統計表 ID" を含む DataFrame
) をそのまま渡してもよい。複数のレコードがある場合は全データを連結して返す。
df = jpd.DataReader(target, 'estat', appid=key)
df
出典:「平成26年全国消費実態調査調査結果」(総務省統計局)
取得したデータを集計してみる。各属性に対応する値は "value" カラムに含まれている。まず、カラム名を簡潔なものに変更する。
df.columns =[u'value', u'世帯区分', u'品目分類表', u'地域', u'表章項目', u'男女', u'年齢階級', u'購入形態']
また、dtypes
を見ると全ての列が object
型になっている。通常、"value" には数値が入るため、jpd.DataReader
は "value" が数値に変換できる場合は自動で変換するのだが、このデータでは何らかの理由で失敗しているようだ。
df.dtypes # value object # 世帯区分 object # 品目分類表 object # 地域 object # 表章項目 object # 男女 object # 年齢階級 object # 購入形態 object # dtype: object
pd.to_numeric
で数値に変換しようとすると ValueError
が発生する。データを見ると "value" にハイフン "-" がいくつか使われているようだ (やめてくれ...)。
文字列処理してもよいが、今回は特に何もしなくても以降の処理で解決されるため、とりあえずそのままにしておく。
1/9 補足 v0.2.1 では "-" を欠損として扱うように修正済み。
pd.to_numeric(df['value']) # ValueError: Unable to parse string df['value'].str.isnumeric() # 時間軸(年次) # 2014-01-01 True # 2014-01-01 True # 2014-01-01 True # 2014-01-01 False # ... # 2014-01-01 False # 2014-01-01 False # 2014-01-01 False # 2014-01-01 False # Name: value, dtype: bool
"品目分類表" の値をみるとかなり細かい項目に分けられていることがわかる。
統計調査に利用された調査票 を参照すると、調査形式は家計簿のようなフォーマットに任意の品名を書き込むもののようだ。品目分類を被調査者が記入する欄はなく、集計時に家計簿を品目分類表に従って分類しているのだろう。
df[u'品目分類表'].unique() # array([u'集計世帯数', # u'世帯数分布(抽出率調整)', # u'世帯数分布(抽出率調整)(1万分比)', # ..., u'仕送り金', # u'国内遊学仕送り金', # u'他の仕送り金'], dtype=object)
データから "すし" を含むレコードを抽出してみる。...弁当とは? この調査票には詳細が記載されていないようだが、他の調査を見ると スーパーで買うパックの寿司を指しているものと思う (おにぎりは別項目)。
filtered = df[df[u'品目分類表'].str.contains(u'すし')] filtered
抽出されたレコードの
"value" には 数値として不正な文字列は含まれないため、pd.to_numeric
で数値に変換できる。
filtered['value'] = pd.to_numeric(filtered['value']) filtered.dtypes # value int64 # 世帯区分 object # 品目分類表 object # 地域 object # 表章項目 object # 男女 object # 年齢階級 object # 購入形態 object # dtype: object
Series.nunique
で各列に含まれるユニークな値の数を調べる。"男女", "年齢階級", "購入形態" でレコードが分かれているため、それら 3 つをキーにして集計してやればよい。
filtered.apply(lambda x: x.nunique()) # value 76 # 世帯区分 1 # 品目分類表 1 # 地域 1 # 表章項目 1 # 男女 3 # 年齢階級 8 # 購入形態 4 # dtype: int64 sushi = pd.pivot_table(filtered, index=[u'男女', u'年齢階級'], columns=u'購入形態', values='value', aggfunc='sum') sushi
"購入形態" (支払い方法) には興味がないので、"合計" の値だけを抽出してプロットする。
60 代 男性 単身者 は "すし(弁当)" への消費金額が比較的多いようだ。金額的に月 1 〜 2 回買っている感じだろうか。また女性も一部男性と比べ高い。
sushi = sushi[[u'合計']] sushi.plot.bar(ylim=(0, 1000))
追加データでの確認
同じ統計調査に "二人以上の世帯" のデータも含まれているので、同項目をみてみる。先ほどと同じように、まず 対象の統計表 ID を調べる。世帯別の集計になるため、男女/年齢といった区分はないが、品目別の支出がわかるデータを探す。
indexer2 = tables.index.str.contains(u'品目別1世帯当たり1か月間の支出') tables[indexer2]
table2 = tables[indexer2].index[3] target2 = dlist[dlist[u'統計表題名及び表番号'] == table2] target2
見つけた 統計表 ID から実データを取得する。
df2 = jpd.DataReader(target2, 'estat', appid=key)
df2
カラム名を変更し、"すし" かつ 地域が "全国" のデータのみを抽出する。
df2.columns = [u'value', u'世帯区分', u'品目分類表', u'地域', u'表章項目'] sushi2 = df2[df2[u'品目分類表'].str.contains(u'すし') & (df2[u'地域'] == u'全国')] sushi2[u'value'] = pd.to_numeric(sushi2[u'value']) sushi2
この数値が二人以上世帯での消費金額の平均になる。先のグラフに重ねてプロットする。
ax = sushi.sum(axis=1).plot.bar(ylim=(0, 1000)) ax.axhline(y=sushi2.iloc[1, 0], color='red')
単身者で 二人以上世帯の消費金額とほぼ同じ金額を使っていれば消費が多いと言ってよさそうだ。単純な見方をすると 料理は面倒だし外食は気疲れする...と感じる頻度が高い層が買っているのだろうか。被調査者によってかなり偏りがあると考えられるので、ここまで細項目を取るなら分布が見てみたい。
Pythonによるデータ分析入門 ―NumPy、pandasを使ったデータ処理
- 作者: Wes McKinney,小林儀匡,鈴木宏尚,瀬戸山雅人,滝口開資,野上大介
- 出版社/メーカー: オライリージャパン
- 発売日: 2013/12/26
- メディア: 大型本
- この商品を含むブログ (12件) を見る