今回は業務でクラスタリングを行う必要がありその過程でPythonのScipyというライブラリを使用して階層型クラスタリングを行い、その結果をデンドログラムをプロットするみたいなことをやってみたので、流れなどをメモしておこうと思います。
まずは元になるデータを作成します
import pandas as pd data = [ ['A',70,100] , ['B',60,10] , ['C',77,30] , ['D',90,80] , ['E',30,50] , ['F',20,10] , ['G',60,70] , ['H',30,40] , ['I',60,90] ] df = pd.DataFrame(data, columns=['名前','国語','数学']) df
<実行結果>
これを行列に整形します。形式としてはデータフレームのインデックスにラベル(今回なら名前)が格納され、データフレームの値はすべて数値型が格納されている行列とします。
#名前の列をインデックスに指定 df.index = df['名前'] # 列削除 del df['名前'] df
<実行結果>
階層型クラスタリング&デンドログラムをプロットするサンプルコード
階層型クラスタリングにも色々種類がありますが、基本的にはウォード法で問題ありません。
!pip install japanize-matplotlib import japanize_matplotlib #階層的クラスタリングはscipyらしい import scipy.spatial.distance as distance from scipy.cluster.hierarchy import dendrogram, ward import matplotlib.pyplot as plt #ward法で分類 linkage_array = ward(df) ax = plt.figure(figsize=(20,20)).gca() dendrogram(linkage_array,labels=df.index) bounds = ax.get_xbound() plt.xticks(fontsize=24) plt.xlabel("ラベル",fontsize=18) plt.ylabel("クラスターの距離",fontsize=18)
コードの簡単な説明になりますが、まずjapanize_matplotlibはMatplotlibがそのままだと日本語のプロットで文字化けするので使用しています。(なので日本語が絡まないデータの場合は定義不要です)
次にlabels=df.index でクラスタリングで分類されたラベルの列を指定しています。これがないとデータのラベルにはデータのインデックスの数字が割り振られます。次にlinkage関数の引数methodで階層型クラスタリングの手法を選択します。
、
今回のように「ward」がウォード法となっています。この他にも、重み付き平均法と呼ばれる「weighted」、重心法と呼ばれる「centroid」「single」が最小結合法、「complete」が最大結合法、「average」が群平均法の6つの手法が用意されています
また、引数metricで使用する距離の種類を選択します。「距離」には実は山のように種類があるのですが、類似度の算出する際に使用する「距離」は基本ユーグリッド距離(eulidean)なので、特段理由が無ければこれを選択しておけば良いです。レコメンドなどで商品間やユーザー間の類似度を測る際などはユークリッドコ距離ではなくサイン類似度を使用した方が良いケースも存在します。
最後のplt.show()により、以下のようにグラフが可視化されて表示されます。
<実行結果>
デンドログラムの表示を横にしたい場合はorientation='left'
を指定してあげるとよいです。他のdenndoroguramの公式ドキュメントはここにありますので他の引数などはここを参考にしてください
公式ドキュメント:https://docs.scipy.org/doc/scipy/reference/generated/scipy.cluster.hierarchy.dendrogram.html
参考:https://qiita.com/oka_1207/items/d49fffb3d31018ec1852
コメント