讃岐小僧のEngineering×Techメモ

未経験から挑戦中のプログラミングや、趣味の野球や狩猟について、その他、ビジネスやテクノロジーをテーマに様々なことをつぶやく場所です。

【Python】政府統計窓口 e-stat API経由でデータを取得する

はじめに

機械学習プロジェクトにて政府統計の総合窓口、e-Stat APIを経由してデータを取得しようと考えている。

f:id:keisuke8925gdk:20190923010633p:plain

特に今回は国政調査のデータを取得して、データセットのカラムを増やしたいと考えている。

とは言ってもちゃんとまずは取得してみないことにはどんなものなのか掴めないので今回はとにかく触るのが目的である。

そのため、matplotlibとかSeabornとかおしゃれな可視化ライブラリを用いてデータを可視化するようなことはしない。 (そういうおしゃれイケメンなことを今後はしたい願望はある)

とにかく触わる」これが最大の目的である。

(あわよくば苦手意識をなくす)

APIを利用する前の事前知識

API Keyの取得については小僧が説明せずとも素晴らしい記事が他に存在するのでその記事を紹介させていただくだけとする。

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

早速データを取得する

とりあえず、モジュール類をインストールする

# モジュールのインポート
import pandas as pd
import numpy as np
import urllib
import urllib.request
import requests
import json

API keyの値をセットする

# API KEYの設定
appId = "Your API Key"

データの取得は下記の通り小僧は書いてみた。

  • APIのバージョンは 最新の3.0を利用。
#JSONデータの取得
def get_json(base_url, params):
    params_str = urllib.parse.urlencode(params) ## URLをエンコードする
    url = base_url + params_str ## リクエストパラメータを作成
    json = requests.get(url).json() ## 指定のURLにリクエストを送る
    return json

def main():
    base_url = "http://api.e-stat.go.jp/rest/3.0/app/json/getStatsData?"
    statsDataId="0003152960"  ## 統計票ID
    searchKind=2 ## 検索するデータの種別を指定する
    limit=2 #所得件数 

#パラメータセット
    params = {
        "appId" : appId,
        "statsDataId" : statsDataId, ## これは指定が必須
        "limit" : limit,
        "searchKind": searchKind
    }
    
    json=get_json(base_url, params)
    return json

res = main()

上記でデータの取得結果はresに格納された状態となりました。

ちょっと思ったのはRubyの場合はメソッド内で明示的にreturnしなくてもいいけどPythonは明示的に書かないと呼び出し元に値が戻らないんだなぁ〜って。

初めての言語がRubyだったからそういう言語もあるのかって。
(ていうか、明示的に書くのが全体的にみてスタンダードですかね?)

API Requestの結果確認

APIリクエストの結果は下記で確認できる。
これに以上がある場合は何かしらエラーがある場合だ。

print(res["GET_STATS_DATA"]["RESULT"]["ERROR_MSG"])

f:id:keisuke8925gdk:20190923013905p:plain

データ個数などの確認

またまたデータの値ではなくメタ情報ですが、下記のようにデータの総数や本リクエストで取得したデータが何番目〜何番目のものなのかなどを確認することもできます。

data_total = res["GET_STATS_DATA"]["STATISTICAL_DATA"]["RESULT_INF"]["TOTAL_NUMBER"]
data_from = res["GET_STATS_DATA"]["STATISTICAL_DATA"]["RESULT_INF"]["FROM_NUMBER"]
data_to = res["GET_STATS_DATA"]["STATISTICAL_DATA"]["RESULT_INF"]["TO_NUMBER"]

print("データ総数は{}個でした。\n今回は{}~{}個までのデータを取得しています。".format(data_total, data_from, data_to))

f:id:keisuke8925gdk:20190923013800p:plain

とりあえずメタ情報色々表示させてみます

table_info = res["GET_STATS_DATA"]["STATISTICAL_DATA"]["TABLE_INF"]

id = table_info["@id"]
stat_name = table_info["STAT_NAME"]["$"]
stat_id = table_info["STAT_NAME"]["@code"]

gov_name = table_info["GOV_ORG"]["$"]
gov_id = table_info["GOV_ORG"]["@code"]

statistical_name = table_info["STATISTICS_NAME"]
statistical_title = table_info["TITLE"]["$"]
statistical_id = table_info["TITLE"]["@no"]

print("■ 統計調査名は\x1b[34m「{}」\x1b[mです。IDは\x1b[34m「{}」\x1b[mです。\n".format(stat_name, stat_id))
print("■ \x1b[34m「{}」\x1b[mによる調査です。IDは\x1b[34m「{}」\x1b[mです。\n".format(gov_name, gov_id))
print("■ この調査表の名前は\x1b[34m「{}」\x1b[mです。\n".format(statistical_name))
print("■ 調査タイトル名は\x1b[34m「{}」\x1b[mです。\n".format(statistical_title))

f:id:keisuke8925gdk:20190923013604p:plain

APIのクラスを確認する

クラスの確認はこちらで

class_data=res["GET_STATS_DATA"]["STATISTICAL_DATA"]["CLASS_INF"]["CLASS_OBJ"]

クラスオブジェクトに関しては下図をみていただいた方が良いと思う。

f:id:keisuke8925gdk:20190923014252p:plain

図のように{ '@id' : 'tab'...}のような構造でそれぞれの統計データをソートできるようになっている。

この@idに対応するtabや今回統計表IDだとcat01とかの属性値を確認してみる

下はtabのデータの説明で、要は6、7、795でソートできるということ。

6 = 一般世帯数
7 = 一般世帯人員
795 = 1世帯あたりの人員

なので例えば、一般世帯数のデータのみを抽出しようとするならtagの値を6とすれば良い。

このことは表章事項と読んでいるみたいで、取得した後でわざわざソートをせずとも、APIリクエストの段階でそーとしたデータを取得することも可能なようだ。

f:id:keisuke8925gdk:20190923015936p:plain

class_data=res["GET_STATS_DATA"]["STATISTICAL_DATA"]["CLASS_INF"]["CLASS_OBJ"]

df_tab = pd.DataFrame(class_data[0]["CLASS"])
df_tab

f:id:keisuke8925gdk:20190923014943p:plain

それぞれのデータにおいても同様に抽出して、それぞれのデータの表す意味を確認することができる。

class_obj_cat01 = class_data[1]["@name"]
class_obj_cat01_id = class_data[1]["@id"]

print("\n表章項目は「{}」で表章IDは{}です".format(class_obj_cat01, class_obj_cat01_id))

df_cat01 = pd.DataFrame(class_data[1]["CLASS"])
df_cat01

f:id:keisuke8925gdk:20190923020453p:plain

これ、今回は表章項目と表章IDと言っていますが、正しくは項目コードかもしれないので要注意。

最後にデータ取得

これまではひたすらにメタデータを取得してきましたが、ここで初めて値を取得しようと思います。

df_data = pd.DataFrame.from_dict(res["GET_STATS_DATA"]["STATISTICAL_DATA"]["DATA_INF"]["VALUE"])

df_data.head()

f:id:keisuke8925gdk:20190923020813p:plain

値はこれで取得できます。

すごくわかりずらいが、今回は全体で8052件のデータがあるのだが一つのレスポンスに同系統の3種類のデータが入っていることになっている。

なぜならtab:表章項目?を指定していないから。 今一度記載するが、下記のデータが入っていて

6 = 一般世帯数
7 = 一般世帯人員
795 = 1世帯あたりの人員

これらがそれぞれ2684件ずつ、合計8052件入っている。

なんともややこしい、、、

これ、統計表IDを指定したら、メタデータを確認して目的のデータを取得するように間違いなくパラメータを変えてデータを取得した方が良い。

だって処理めんどくさいし。

これらを頑張って、DataFrameで結合しまくった処理もありますが見苦しいので今回はここまでにしておきます。