クラスタリングとは
前回は、機械学習を行うための環境を構築し、簡単な計算やCSV・エクセルの読み込みまで行ない、Pythonプログラミングへの第一歩を踏み出しました。今回は、教師なし学習の1つであるクラスタリングを扱い、機械学習の世界へと入っていきましょう。
第1回で説明したように、クラスタリングは、教師データを学習させずに与えられたデータから規則性などの意味のある情報を見つけ出す手法です。つまり、いくつかの変数データをもとに、類似性のあるデータをまとめる作業となります。それでは実際に、オープンデータを用いてクラスタリングをやっていきましょう。
データの準備
今回は、各都道府県の物価データを用いて、類似している県ごとにいくつかのグループに分類してみましょう。政府統計の総合窓口e-statから、消費者物価地域差指数というデータをダウンロードし、必要なデータを抽出したものを用意しました。こちらから、そのデータをダウンロードできます。もとのデータを知りたい方は、e-statから、小売物価統計調査>構造編>10大費目別消費者物価地域差指数というデータを探してみてください。
さて、前回の記事を思い出しながら、Pythonでデータを読み込んでみましょう。ダウンロードしたCSVファイルをJupyter Notebookの作業フォルダ(MyNaviフォルダ)にコピーします。その後、Anaconda-Navigatorを立ち上げ、その中からJupyter NotebookのLaunchを選択し、Jupyter Notebookを立ち上げてください。作業フォルダに移動すると、先ほどコピーしたCSVファイルが確認できると思います。早速、右上のNewから、Python3を選択し、Notebookを立ち上げます。まずは、左上のタイトルを適当なファイル名に変更しておきましょう。今回は、ConsumerPricesという名前にしました。 さてまずは、以下のコードを実行し(shift+enter)、データを読み込みます。
import pandas as pd
allData = pd.read_csv('consumerPrices.csv')
allData
このデータは、都道府県別に、10個の項目における物価指数が入っています。全国平均が100で、それよりも高いか低いかが一目でわかります。
簡単なクラスタリングに挑戦
まずは、10項目のうち、「食料」と「水道光熱費」データのみを用いて、進めていきます。散布図による可視化を行った後、クラスタリングを用いて4つのグループに分割してみましょう。まずは、先ほどのデータから、都道府県、食料、水道光熱費のデータを作成します。2個目のセルに、コードを追記し、実行してください。
data1 = allData[['都道府県', '食料', '水道光熱費']]
data1.head()
1行目で、先ほどのallDataから都道府県、食料、水道光熱費のデータを取り出し、新たにdata1を作成しています。データを表示する際に、head()を記述することで、データの上から5行を表示してくれます。今回は、都道府県、食料、水道光熱費が取り出されていることが確認できれば良いので、先頭5行のみを表示しました。 次は、可視化してみましょう。
import matplotlib.pyplot as plt
%matplotlib inline
plt.scatter(data1['食料'], data1['水道光熱費'])
plt.xlabel('Food')
plt.ylabel('Fuel,Light,Water charges')
実行すると、食料、水道光熱費のグラフが出力されます。1行目に記載してあるmatplotlibというのは、ライブラリの一種で、グラフを簡単に描画してくれます。上の2行は、Jupyter Notebookでmatplotlibを使うための準備、それ以降の部分が散布図で描画するデータやラベル等を指定する部分となります。scatterのカッコ内において、data1の「食料」列と「水道光熱費」列を指定しています。この図中の近いデータ同士を、4つに分類する作業がクラスタリングとなります。それでは、実際にクラスタリングを実行してみましょう。以下のコードを実行してみてください。
from sklearn.cluster import KMeans
model1 = KMeans(n_clusters=4, random_state=0)
data1_X = data1[['食料', '水道光熱費']]
model1.fit(data1_X)
y1 = model1.labels_
print(y1)
これで、機械学習が完了です。あまりに簡単で少し拍子抜けした方もいるかと思います。まず、1行目にimportが実行されています。今までの形式と少し違いはありますが、scikit-learn(sklearn)という機械学習ライブラリのなかから、KMeansという手法を呼び出しています。K-Means法は、クラスタリングの代表的な手法の1つで、k個の安定的な重心を見つける手法です。今回の例では、4個の安定的な重心を、各データと重心までの距離によって決めています。
2行目では、モデルの条件を指定しています。今回は、4つに分けるため、n_clustersに4を指定しています。K-Means法は一部乱数を使用することから、再現性がなかなか取りにくいのですが、random_stateを同じ値(今回の場合は0)に指定することで、必ず同じ結果が算出されます。逆に、random_stateを変えると、分類結果が変化するので試してみるとよいと思います。
3行目は、データを機械学習に入れるためのデータ準備です。データのなかから食料と水道光熱費のみのデータ(都道府県を除去したデータ)を作成しています。4行目では、先ほど作成したデータを用いて、クラスタリングを実行しています。5から6行目で、結果をy1に代入し、出力しています。
出力結果を見ると、0から3の4つの数字がランダムに並んでいるように見えますが、これは、一番左から順番に都道府県の分類結果を表示していることになります。このままだと見にくいので、少しデータを加工し、可視化してみましょう。
まずは、データを加工し、分類結果順に並び替えてみます。
data1_results = data1.copy()
data1_results['分類結果'] = y1
data1_results.sort_values('分類結果')
新たにdata1_resultsを作成した後、先ほど出力したy1の分類結果を、data1_resultsに追加し、sort_valuesで分類結果の順番に並び替えて一覧を出力しています。これによって、どの都道府県が同じグループとして分類されたかがわかります。興味のある都道府県を探してみましょう。
次に可視化です。
plt.scatter(data1_results['食料'], data1_results['水道光熱費'], c=data1_results['分類結果'])
plt.xlabel('Food')
plt.ylabel('Fuel,Light,Water charges')
4つの色で、分割できているのが確認できたでしょうか。これが、「食料」「水道光熱費」という2つの変数に対して、クラスタリングを行なった結果です。距離が近い都道府県ごとにグループ化されているのがわかります。
変数を拡張してクラスタリングしてみる
これまでは、イメージをつかんでもらうために2つの変数を用いてクラスタリングを行なってきました。しかし、このままだと、食料と水道光熱費の物価が近い都道府県をグルーピングしただけです。
そこで、ここからは、もともとあった10項目すべてにおいてクラスタリングを実行し、同じように4つのグループに分けてみましょう。作業としては、先ほどと同様に、クラスタリング用に都道府県を除去したデータを作成した後、クラスタリングを実行し、最後に可視化してみます。
まずは、データ加工です。
data2 = allData.copy()
data2_X = data2.drop('都道府県', axis=1)
data2_X.head()
まず、allDataをコピーしたdata2を作成し、さらに、都道府県の列を削除したdata2_Xを作成しました。head()で、先頭5行を出力すると、都道府県以外の物価10項目があるのが確認できます。 それでは、早速、クラスタリングを実行し、データの一覧まで作成しましょう。
model2 = KMeans(n_clusters=4, random_state=0)
model2.fit(data2_X)
y2 = model2.labels_
data2_results = data2.copy()
data2_results['分類結果'] = y2
data2_results.sort_values('分類結果')
先ほどすでにsklearnをimportしてあるため、今回は新たにimportする必要はありません。先ほどのクラスタリングモデルと区別するため、model2という名前でモデルを作成しました。その後のコードはまったく同じです。これによって、先ほどと同様に、クラスタリングの結果を分類結果の順番に並び替えて、一覧で出力できます。自分のゆかりのある都道府県を探してみましょう。自分にとって意外な県が、同じグループに属していることはありますか?
さらに、先ほどの食料、水道光熱費を用いて可視化してみましょう。
plt.scatter(data2_results['食料'], data2_results['水道光熱費'], c=data2_results['分類結果'])
plt.xlabel('Food')
plt.ylabel('Fuel,Light,Water charges')
この結果は、先ほどと大きく異なるかと思います。今回は、10個の変数において計算を行なっているため、食料、水道光熱費だけの2次元グラフを作成しても、一見すると、きれいに分類されているかわかりません。きれいに分類されているかどうかを見たくても、10次元を可視化することは不可能です。
それでは、この分類が正しいかどうかは何が証明してくれるのでしょうか。実は、そこがクラスタリングなどの教師なし学習の難しい部分で、正しいかどうかはあくまでも人間の主観的な部分に依存してしまいます。そのため、客観的かつ決定的な証拠を突きつけることは難しいです。ただ一方で、今回のように正解データがなくても簡単に扱えるため、探索的にデータの規則性を見つけるには有効な手段と言えるでしょう。
さらにいろいろ試してみたい方にオススメなのが、データを拡張することです。今あるデータをもとに、物価以外の都道府県情報を追加して、クラスタリングを実行してみるとよいと思います。最も簡単に追加する方法は、もとのCSVファイルを編集し、新しくエクセルもしくはCSVファイルを作成することでしょう。冒頭で述べたe-statから取得してもよいですが、もう少し簡単なデータを扱うサイトとして以下のようなサイトがあります。それ以外にもいろいろ探して見ると良いと思います。
さて、今回は、教師なし学習の1つであるクラスタリングを取り扱いました。コンピュータと対話しながらデータを探索していくイメージは湧きましたでしょうか。クラスタリングは探索的な手法とあるように、正解はありません。まずは、いろんなデータを用意して、クラスタリングで遊んでみてください。
次回からは、教師あり学習を扱っていきます。
著者プロフィール
下山輝昌
大手電機メーカーにて、ハードウェアの研究開発に従事した後、独立。独立後はソフトウェア、データ分析等において実務経験を積むとともに、数社を共同創業。その中でも合同会社アイキュベータでは、人工知能・IoTなどの可能性や方向性を研究している。最近では、オープンデータに着目し、オープンデータ活用のためのwebサービスの立ち上げ、オープンデータ×IoTによる価値創出を1つのテーマに取り組んでいる。