2018年7月22日日曜日

Pythonとe-StatのAPIで統計データを取得する

都道府県別の飲み物の購入額をk-means法でクラスタリングするではe-Statからcsvをダウンロードして利用したが、e-StatにはAPIがあって、さまざまな統計データをプログラムで取得できる。Python3でe-StatのAPIでデータを取得して、最終的にPandasのDataFrameに変換する手順をまとめておく。


環境


Raspbian JessieとPython3.4.2。



1.アプリケーションIDの取得


APIを使用するにはアプリケーションIDが必要で、それを取得するにはまずe-Statの「新規登録」でユーザー登録をする。ユーザー登録が完了したらログインして、「マイページ」ページの「API機能(アプリケーションID発行)」へ移動する。名称やURLを入力する必要があるが、利用ガイドにあるように、公開サイトで利用するのでなければURLは「http://localhost」でOK。名称も後で変更できるので、ちょっと試すだけなら、とりあえず深く考えずにつけても問題なさそう。

「発行」ボタンを押すとappIdの欄にアプリケーションIDが表示されるので、これをどこかにコピーしておく。


2.リクエストURLの取得


APIを使用するためのリクエストURLを取得する。URLは各データのページで取得するデータを表示したうえで「API」ボタンを押すことで得られる。

以下のようなポップアップウィンドウにAPI用のURLが表示される。

今回は都道府県別の飲み物の購入額をk-means法でクラスタリングすると同じデータを取得する。2009地域は全国と各都道府県、2009品目分類は「緑茶」「紅茶」「コーヒー」のみで、あとは合計値が選択されるようにしておく。以下は選択した状態の画面。

「表示を更新」を押すと選択したデータが表示される。この画面で「API」ボタンを押して表示されるURLをコピーしておく。


3.APIによるデータの取得


APIで取得できるデータ形式はXML、JSON、JSONP、CSVの4種類。取得するデータ形式に合わせてコピーしておいたAPIのURLを変更し、さらにアプリケーションIDを設定してURLを使う。API仕様の詳細はAPI仕様を参照。

JSONで取得するPython3のコードは以下の通り。

import urllib.request
import json

# e-Stat APIのappId
appId = 'コピーしておいたappIdをここにペーストする'
# APIのリクエストURL
# コピーしておいたURLのhttpをhttpsにしておく
url = 'https://api.e-stat.go.jp/rest/2.1/app/getStatsData?cdCat03=47001&cdCat04=48001&cdArea=00000%2C01000%2C02000%2C03000%2C04000%2C05000%2C06000%2C07000%2C08000%2C09000%2C10000%2C11000%2C12000%2C13000%2C14000%2C15000%2C16000%2C17000%2C18000%2C19000%2C20000%2C21000%2C22000%2C23000%2C24000%2C25000%2C26000%2C27000%2C28000%2C29000%2C30000%2C31000%2C32000%2C33000%2C34000%2C35000%2C36000%2C37000%2C38000%2C39000%2C40000%2C41000%2C42000%2C43000%2C44000%2C45000%2C46000%2C47000&cdCat02=H1000%2CH1010%2CH1050&cdCat01=07001&appId=&lang=J&statsDataId=0003018185&metaGetFlg=Y&cntGetFlg=N&sectionHeaderFlg=1'

def url_json(url):
    """
    URLをJSON取得用に変更する
    「/apps/」のあとに「json/」を追加
    """
    return url.replace('/app/', '/app/json/')

def set_appid(url):
    """
    URLにappIdを設定する
    「appId=」のあとにappIdを追加
    """
    return url.replace('appId=', 'appId=' + appId)

def get_estat_json():
    request_url = set_appid(url_json(url))

    with urllib.request.urlopen(request_url) as f:
        res = json.loads(f.read().decode('utf8'))

    return res

def main():
    res = get_estat_json()
    # 取得したデータ(JSON)を表示
    print(json.dumps(res, indent=2, sort_keys=True))

if __name__ == '__main__':
    main()

実行すると以下のようにJSONでデータが得られる。



4.JSONをPandasのDataFrameに変換する


後の処理をやりやすくするためにJSONをPandasのDataFrameに変換する。まずはJSONをpandas.io.json.json_normalizeでDataFrameに変換し、pandas.DataFrame.pivotで都道府県をインデックス、品目をカラムにする。
import urllib.request
import json
import pandas as pd
from pandas.io.json import json_normalize

# e-Stat APIのappId
appId = 'コピーしておいたappIdをここにペーストする'
# APIのリクエストURL
# コピーしておいたURLのhttpをhttpsにしておく
url = 'https://api.e-stat.go.jp/rest/2.1/app/getStatsData?cdCat03=47001&cdCat04=48001&cdArea=00000%2C01000%2C02000%2C03000%2C04000%2C05000%2C06000%2C07000%2C08000%2C09000%2C10000%2C11000%2C12000%2C13000%2C14000%2C15000%2C16000%2C17000%2C18000%2C19000%2C20000%2C21000%2C22000%2C23000%2C24000%2C25000%2C26000%2C27000%2C28000%2C29000%2C30000%2C31000%2C32000%2C33000%2C34000%2C35000%2C36000%2C37000%2C38000%2C39000%2C40000%2C41000%2C42000%2C43000%2C44000%2C45000%2C46000%2C47000&cdCat02=H1000%2CH1010%2CH1050&cdCat01=07001&appId=&lang=J&statsDataId=0003018185&metaGetFlg=Y&cntGetFlg=N&sectionHeaderFlg=1'

def to_dataframe(res):
    item = [] # 品目のリスト
    pref = [] # 都道府県のリスト
    for obj in res['GET_STATS_DATA']['STATISTICAL_DATA']['CLASS_INF']['CLASS_OBJ']:
        # 分類などの出力
        if isinstance(obj['CLASS'], dict): # dict
            print(obj['@id'], obj['@name'], obj['CLASS']['@name'])
        else: # list
            id = obj['@id']
            for cat in obj['CLASS']:
                print(id, obj['@name'], cat['@name'], cat['@code'])
                if id == 'cat02': # 2009品目分類
                    item.append(cat['@name'])
                elif id == 'area': # 2009地域
                    pref.append(cat['@name'])

    # JSONをDataFrameに変換
    df = json_normalize(res['GET_STATS_DATA']['STATISTICAL_DATA']['DATA_INF']['VALUE'])
    # 必要なカラムのみ抽出
    df = df.loc[:, ['$', '@area', '@cat02']]

    # 都道府県をインデックス、品目(緑茶、紅茶、コーヒー)をカラムにする
    g = df.pivot(index='@area', columns='@cat02')
    g.index = pref
    g.columns = item
    g = g.iloc[1:48] # 「全国」の行を省く

    return g

def main():
    res = get_estat_json()
    # 取得したデータ(JSON)を表示
    print(json.dumps(res, indent=2, sort_keys=True))

    df = to_dataframe(res)
    print(df)

if __name__ == '__main__':
    main()


5.結果


4のスクリプトを実行すると以下の結果が得られる。


都道府県別の飲み物の購入額をk-means法でクラスタリングするでダウンロードしたcsvからDataFrameに変換したデータと比べると、同じ数値になっている。
 

0 件のコメント:

コメントを投稿