7
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Pythonで階層クラスタリングしデンドログラムを表示

Last updated at Posted at 2021-08-22

はじめに

クラスタリングといえば、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)

image.png

素晴らしい。10個のクラスターの関係が一目瞭然である。
ちなみにグラフ中の()は、各クラスターの要素数を示している。このデータを手掛かりに、model.labels_ で得られるクラスタとの紐づけを行ってほしい。

なお、plot_dendrogram 関数 の引数pでデンドログラムのクラスタ数を変更できるため、このpを変えつつデンドログラムを見ながら最適なクラスタ数を決めてもよいだろう。

参考

7
7
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?