ボトムアップ式のクラスタリングのグループ化

データ作成

shape: (5, 3) のランダム行列を作成

import pandas as pd
import numpy as np

np.random.seed(123)

variables = ['X', 'Y', 'Z']
labels = ['ID_0', 'ID_1', 'ID_2', 'ID_3', 'ID_4']

X = np.random.random_sample([5, 3])*10

## pandas のデータフレームに変更
df = pd.DataFrame(X, columns=variables, index=labels)

距離の計算

from scipy.spatial.distance import pdist, squareform

## pdist : 距離の計算
## squareform : pdist にて算出した圧縮済みの距離行列から対称行列に変換
row_dist = pd.DataFrame(squareform(pdist(df, metric='euclidean')),
                        columns=labels,
                        index=labels)
from scipy.cluster.hierarchy import linkage
# method='complete' : 完全連結法、 クラスタの中で一番距離の遠い点が違い順で凝縮する
row_clusters = linkage(pdist(df, metric='euclidean'), method='complete')

階層的クラスタリングの実行

# no. of items in clust : クラスタの個数 
pd.DataFrame(
    row_clusters,
    columns=[
        'row label 1',
        'row label 2',
        'distance',
        'no. of items in clust.'
    ],
    index=['cluster %d' % (i +1) for i in range(row_clusters.shape[0])]
)
  • sklearnでの実行
from sklearn.cluster import AgglomerativeClustering
ac = AgglomerativeClustering(
    n_clusters=3,
    affinity='euclidean',
    linkage='complete'
)
labels = ac.fit_predict(X)
print('Cluster labels: %s' % labels)
Cluster labels: [1 0 0 2 1]

連結行列を樹形図にて表す

from scipy.cluster.hierarchy import dendrogram

row_dendr = dendrogram(
    row_clusters,
    labels=labels,
)
plt.ylabel('Euclidean distance')
plt.tight_layout()
plt.show()

ヒートマップによる可視化

fig = plt.figure(figsize=(8, 8), facecolor='white')
## x 軸の位置、y 軸の位置、幅、高さ
axd = fig.add_axes([0.09, 0.1, 0.2, 0.6])
## orientation : 回転
row_dendr = dendrogram(row_clusters, orientation='left')

## クラスタリングのラベルは 'leaves'から取得する。
## ヒートマップは右側に配置する
df_rowclust = df.iloc[row_dendr['leaves'][::-1]]
axm = fig.add_axes([0.23, 0.1, 0.6, 0.6])
cax = axm.matshow(df_rowclust, interpolation='nearest', cmap='hot_r')

axd.set_xticks([])
axd.set_yticks([])
for i in axd.spines.values():
    i.set_visible(False)
    
fig.colorbar(cax)
axm.set_xticklabels([''] + list(df_rowclust.columns))
axm.set_xticklabels([''] + list(df_rowclust.index))
plt.show()