2018年6月24日日曜日

都道府県別の飲み物の購入額をk-means法でクラスタリングする

e-Statには全国消費実態調査データというものがあって、さまざまなものにどのくらいの金額が使われているかがわかる。Python3とそのライブラリのscikit-learnを使って、このデータをk-means法でクラスタリングする。

全国消費実態調査データには集計方法などが違ういくつかのデータセットがあるが、今回使うのは全国消費実態調査 平成21年全国消費実態調査 全国 購入先・購入地域編[二人以上の世帯] 【品目別1世帯当たり1か月間の支出】 地域,購入地域,購入先別データセットにある「緑茶」「紅茶」「コーヒー」の都道府県別購入金額。


環境


Bash on Ubuntu on Windows


Jupyter Notebook



データの取得


e-Statからデータを取得する。取得するのは全国消費実態調査 平成21年全国消費実態調査 全国 購入先・購入地域編[二人以上の世帯] 【品目別1世帯当たり1か月間の支出】 地域,購入地域,購入先別データセット。デフォルトだと項目数が多すぎるので、表示項目選択で項目を絞る。


「2009品目分類」では「緑茶」「紅茶」「コーヒー」を選択し、「2009-47購入地域」と「2009-48購入先」は合計のみ、「2009地域」は全国と都道府県を選択する。表示を更新して、csvをダウンロード。このときに注釈は使わないので「注釈を表示しない」のチェックを外しておく。

csvはsurvey_drink.csvというファイル名で保存しておく。


csvからデータの抽出


ダウンロードしたcsvからPython3で必要なデータを抽出してPandasのDataFrameにする。

import codecs
import pandas as pd

def import_estat_csv():
    with codecs.open('survey_drink.csv', 'r', 'shift_jis', 'ignore') as f:
        # 都道府県をインデックスとして読み込む
        df = pd.read_csv(f, index_col=7, skiprows=10, skipinitialspace=True)

    # 「緑茶」「紅茶」「コーヒー」列のみを抽出
    df = df[df.columns[12:]]

    # 都道府県の行のみ抽出
    return df.iloc[1:48]

if __name__ == '__main__':
    df = import_estat_csv()

    # DataFrameの確認
    print(df)

DataFrameの中身は以下のようになる。


クラスタリング用にデータの計算


「緑茶」「紅茶」「コーヒー」の消費金額は都道府県ごとに合計金額がまちまち。このままクラスタリングすると合計金額が多い・少ないかが影響してクラスタリングされてしまうかもしれないので、都道府県ごとに「緑茶」「紅茶」「コーヒー」の合計に対する割合を計算してクラスタリングする。以下はcsvを読み込んで作成したDataFrameで「緑茶」「紅茶」「コーヒー」の合計に対する割合を計算するコード。

import codecs
import pandas as pd

def calc_rate(df):
    df['sum'] = df[df.columns[0]] + df[df.columns[1]] + df[df.columns[2]]
    df['緑茶'] = df[df.columns[0]] / df['sum']
    df['紅茶'] = df[df.columns[1]] / df['sum']
    df['コーヒー'] = df[df.columns[2]] / df['sum']

    # 「緑茶」「紅茶」「コーヒー」の、都道府県ごとの購入金額の割合
    return df[df.columns[4:]]

if __name__ == '__main__':
    df = import_estat_csv()

    df = calc_rate(df)

    print(df)

以下のように各飲み物の都道府県ごとの割合が計算される。



k-means法によるクラスタリング


scikit-learnのKMeansクラスを使ってk-means法によりクラスタリングする。k-means法は初期値を設定する必要があるが、KMeansではデフォルトで初期値設定が不要のk-means++法が使われる。また、k-means法ではクラスター数をはじめに決める必要がある。ここではとりあえず5にする。

import codecs
import pandas as pd
from sklearn.cluster import KMeans

def clustering(df):
    # 5つにクラスタリング
    df['cluster'] = KMeans(n_clusters=5, random_state=0).fit_predict(df.as_matrix())

    # クラスタリング結果の確認
    groups = df.groupby('cluster')
    for c, g in groups:
        print('Cluster', c)
        print(g.index.values)

    return groups

if __name__ == '__main__':
    # csvのデータを読み込んでPandasのDataFrameに
    df = import_estat_csv()

    # 「緑茶」「紅茶」「コーヒー」の合計に対する割合を計算
    df = calc_rate(df)

    # クラスタリングと結果表示
    clustering(df)

以下はクラスタリングの結果。緑茶の生産量が多い静岡県、鹿児島県が同じクラスターにに属している。また、東京とその周辺、大阪とその周辺がそれぞれ同じクラスターに属しているので、関東と関西の違いがあるのかもしれない。
 


クラスタリング結果のグラフ化


文字だけ見てもどういう結果になったか分かりにくいので、クラスターごとの平均値をmatplotlibでグラフ化する。

import codecs
import pandas as pd
from sklearn.cluster import KMeans

%matplotlib inline
from IPython.core.pylabtools import figsize
import matplotlib.pyplot as plt

def draw_bar(groups):
    means = groups.mean()
    errors = groups.std()

    fig = plt.figure(figsize=(8, 6))
    ax = fig.add_subplot(1,1,1)
    means.plot.bar(color=['green', 'orange', 'brown'], yerr=errors, ax=ax)
    ax.set_xticklabels(means.index.values, rotation=0)
    plt.show()

if __name__ == '__main__':
    # csvのデータを読み込んでPandasのDataFrameに
    df = import_estat_csv()

    # 「緑茶」「紅茶」「コーヒー」の合計に対する割合を計算
    df = calc_rate(df)

    # クラスタリングと結果表示
    groups = clustering(df)

    # クラスターごとの平均値の棒グラフ
    draw_bar(groups)

クラスターごとの平均購入額割合

静岡県が属するクラスター1の緑茶の購入額割合が多いのは納得。一方、クラスター4に属する京都府は意外と緑茶の購入額割合が多くない。また、首都圏が属するクラスター2は緑茶とコーヒーの購入額割合が拮抗していており、関西圏が属するクラスター4はコーヒーの購入額割合が緑茶に比べてかなり多い。首都圏と関西圏では傾向に違いがあることがわかる。

0 件のコメント:

コメントを投稿