はじめに
クラスタリングといえば、kmeansが有名であるが、クラスタ数を事前に決めておく必要があることや、分割されたクラスタ間の関係が分かりにくいという欠点があげられる。
このデメリットを解消する手法として階層クラスタリングがある。この手法、scikit-learn には標準で搭載されていないと思い込んでいたのだがこの度あるということが分かった。その名もAgglomerativeClustering。早速使ってみたので紹介したい。
本記事では階層クラスタリングやデンドログラムの詳細については説明はしないので、詳しくは他のサイトを見てほしい。
環境
- scikit-learn 0.24.2
まずはクラスタリング
まずは通常のクラスタリングを実施してみる。
必要モジュールのインポート
必要そうなモジュールを適当にインポート
import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
from scipy.cluster.hierarchy import dendrogram
from sklearn.datasets import load_iris
from sklearn.cluster import AgglomerativeClustering
続いてクラスタリングの実施。今回10クラスタに分割するとする。
ちなみに target_scaling という変数にスケーリング後のデータ(全1272件)が格納されているという想定だ。
model = AgglomerativeClustering(affinity='euclidean',
linkage='ward',
n_clusters=10)
model = model.fit(targets_scaling)
結果を見てみよう。modelのlabels_という変数に、各データに割り当てたクラスタの番号が配列で格納されている。
print(model.labels_)
array([1, 1, 9, ..., 2, 2, 1], dtype=int64)
集計してみると、確かに全1272件のデータが10個のクラスタに割り振られていることが分かる。
np.unique(model.labels_, return_counts=True)
(array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=int64),
array([285, 321, 118, 56, 63, 44, 12, 37, 52, 284], dtype=int64))
デンドログラムの表示
階層クラスタリングのメリットは、クラスタの関係を可視化できることである。
早速デンドログラムで可視化してみよう。デンドログラムはscipyの関数を使って表示することができる。
デンドログラム表示関数の準備
まずはデンドログラムを表示する関数を準備しよう。これはscikit-learnの例をそのまま使っている。
def plot_dendrogram(model, **kwargs):
counts = np.zeros(model.children_.shape[0])
n_samples = len(model.labels_)
for i, merge in enumerate(model.children_):
current_count = 0
for child_idx in merge:
if child_idx < n_samples:
current_count += 1 # leaf node
else:
current_count += counts[child_idx - n_samples]
counts[i] = current_count
linkage_matrix = np.column_stack([model.children_, model.distances_, counts]).astype(float)
dendrogram(linkage_matrix, **kwargs)
先のクラスタリング結果をこの関数を与えればよいのだが、デンドログラム表示関数では全データの距離計算が必要となる。
全データの距離計算を行うためには、以下のようにクラスタ数を指定せずにクラスタリングを行う必要がある。
model = AgglomerativeClustering(affinity='euclidean',
linkage='ward',
distance_threshold=0,
n_clusters=None)
model = model.fit(targets_scaling)
この状態で、デンドログラム表示関数を呼び出すと、無事デンドログラムが表示される。
plot_dendrogram(model, truncate_mode='lastp', p=10)
素晴らしい。10個のクラスターの関係が一目瞭然である。
ちなみにグラフ中の()は、各クラスターの要素数を示している。このデータを手掛かりに、model.labels_
で得られるクラスタとの紐づけを行ってほしい。
なお、plot_dendrogram 関数
の引数p
でデンドログラムのクラスタ数を変更できるため、このp
を変えつつデンドログラムを見ながら最適なクラスタ数を決めてもよいだろう。