scikit-learn

【scikit-learn】DBSCANでクラスタリングする方法

【scikit-learn】DBSCANでクラスタリングする方法

Pythonの機械学習ライブラリであるscikit-learnのDBSCANを使ってクラスタリングを行う方法を解説します。

DBSCANによるクラスタリング

DBSCANは、教師なし学習のクラスタリングに関する手法です。

クラスタリングで代表的な手法としてはk-means法があります。k-means法について気になる方は、「KMeansでk-means法によるクラスタリングをする方法」にまとめていますので興味があればご確認ください。

k-means法では、セントロイドという各クラスタの中心との距離の平方和誤差を小さくするようにクラスタを選んでいく手法です。そのため、クラスタは円形(球形)に必然的になっていきます。このことは、クラスターの大きさが異なったり、データに偏りがある場合に、うまくクラスタリングができないことを意味しています。

DBSCANでは、クラスターに関してデータが密集している部分と疎な部分を分離して考えることができる手法で、クラスターの大きさやデータに偏りがある場合でも対応することが可能です。また、クラスターの数を指定しなくてもよいことも特徴になっています。

DBSCANは、Pythonの機械学習ライブラリであるscikit-learnにてDBSCANとして実装がされています。

本記事では、scikit-learnのDBSCANを使ったクラスタリング実装方法を紹介します。上記で説明したようにk-meansではクラスタリングできないようなデータに対してもクラスタリング可能なことを見ていきましょう。

scikit-learnのDBSCANによるクラスタリング方法

DBSCANの使い方(sklearn.cluster.DBSCAN)

実装例

scikit-learnのmake_moonsでクラスタリング用のデータを用意し、DBSCANを使ってクラスタリングする実装例を以下に示します。

import matplotlib.pyplot as plt
import numpy as np
from sklearn.cluster import DBSCAN
from sklearn.datasets import make_moons


def main():
    """メイン関数"""
    np.random.seed(1)

    # ===== データの生成
    data, label = make_moons(n_samples=500, noise=0.05)

    # ===== DBSCANでのクラスタリング
    dbscan = DBSCAN(eps=0.2, min_samples=5)
    pred = dbscan.fit_predict(data)
    n_c = set(pred)

    # ===== クラスタリング結果を描画する
    fig, ax = plt.subplots(1, 2, figsize=(10, 5))
    # 元データを表示する
    ax[0].scatter(data[:, 0], data[:, 1])
    ax[0].set_title("original data")
    # クラスタリング結果を表示する
    for i in n_c:
        ax[1].scatter(data[pred == i, 0], data[pred == i, 1])
    ax[1].set_title("DBSCAN clustering")
    plt.show()


if __name__ == "__main__":
    main()
DBSCAN クラスタリング

実装内容の解説

上記で紹介した実装例の各部分ごとに内容を解説していきます。

必要モジュールのインポート

from sklearn.cluster import DBSCAN

DBSCANクラスタリングを使用するには、sklearn.clusterからDBSCANをインポートします。他にもnumpy等インポートしていますが、そちらの説明は省略します。

データセットの準備

    np.random.seed(1)

    # ===== データの生成
    data, label = make_moons(n_samples=500, noise=0.05)

データとしては、make_moonsを使って生成しています。引数として指定しているのは以下のような項目です。

  • n_samples:データの点数
  • noise:データに付与するガウスノイズの標準偏差

乱数のシードは、np.random.seedで設定していますが、make_moonsのrandom_state引数で指定することも可能です。

DBSCANクラスタリングの実行

    # ===== DBSCANでのクラスタリング
    dbscan = DBSCAN(eps=0.2, min_samples=5)
    pred = dbscan.fit_predict(data)
    n_c = set(pred)

上記の部分でDBSCANクラスタリングを実行しています。DBSCANでは以下の引数を指定します。

  • eps:データ半径
  • min_samples:eps内のデータ数

DBSCANでは以下のような考え方でクラスタリングを行います。

  1. あるデータ半径であるeps内に、min_samples個のデータがある場合、そのデータ点をコア点とする。
  2. コア点ではないが、コア点から半径eps内に含まれているデータ点をボーダー点とする。
  3. どちらにも満たさないデータ点はノイズ点とする

コア点の集まりからクラスターを構成し、ボーダー点は最も近いコア点の属するクラスターに割り振ります。このように局所的な特徴を捉えることから、偏ったデータなどでもクラスタリングできるようになります。

クラスタリング結果の表示

    # ===== クラスタリング結果を描画する
    fig, ax = plt.subplots(1, 2, figsize=(10, 5))
    # 元データを表示する
    ax[0].scatter(data[:, 0], data[:, 1])
    ax[0].set_title("original data")
    # クラスタリング結果を表示する
    for i in n_c:
        ax[1].scatter(data[pred == i, 0], data[pred == i, 1])
    ax[1].set_title("DBSCAN clustering")
    plt.show()

上記の部分は、元データとクラスタリング結果を横に並べて表示している部分です。

DBSCAN クラスタリング

結果の図を再掲しますが、月形の曲がったようなデータが異なるクラスタにクラスタリングできていることが分かるかと思います。

なお、上記で説明したようにDBSCANはハイパーパラメータであるepsとmin_samplesによって結果が変わります。正直上記はちょうどうまくいくようなパラメータを設定しているのが正直なところです。パラメータを変えたときに、クラスタリング結果にどのような変化が起きるか試してみると面白いでしょう。

k-meansクラスタリングでの実行結果

冒頭にk-meansクラスタリングでは、データの偏りがある場合にうまくいかないというようなことを説明しましたが、実際にmake_moonsのデータに対してk-means法を適用して結果を見てみましょう。DBSCANのメリットがよく分かるかと思います。

import matplotlib.pyplot as plt
import numpy as np
from sklearn.cluster import KMeans
from sklearn.datasets import make_moons


def main():
    """メイン関数"""
    np.random.seed(1)

    # ===== データの生成
    data, label = make_moons(n_samples=500, noise=0.05)

    # ===== KMeansでクラスタリング
    k = 2
    km = KMeans(n_clusters=k)
    pred = km.fit_predict(data)

    # ===== クラスタリング結果を描画する
    fig, ax = plt.subplots(1, 2, figsize=(10, 5))
    # 元データを表示する
    ax[0].scatter(data[:, 0], data[:, 1])
    ax[0].set_title("original data")
    # クラスタリング結果を表示する
    for i in range(k):
        ax[1].scatter(data[pred == i, 0], data[pred == i, 1])
    ax[1].set_title("k-means clustering")
    plt.show()


if __name__ == "__main__":
    main()
k-means クラスタリング moons

プログラムの詳細はDBSCANと同じようなコードなので省略します。k-menasクラスタリングの使い方としては、「KMeansでk-means法によるクラスタリングをする方法」にまとめているので興味があればご確認ください。

上記の結果を見てみると、うまく月形のデータをクラスタリングできていないことが分かります。各色を見てみると何となく円状のクラスタとなっているのが見えてきます。これは、セントロイドという各クラスタの中心との距離の平方和誤差を小さくするようにクラスタを選んでいくというアルゴリズムの特徴により、必然的に円形(又は球形)のクラスタになるためです。

このようにk-meansでは、データが偏ったデータではうまくクラスタリングできない場合があります。DBSCANはハイパーパラメータの設定によるのですが、こういった偏ったデータのクラスタリングにも対応することができます。

まとめ

Pythonの機械学習ライブラリであるscikit-learnのDBSCANを使ってクラスタリングを行う方法を解説しました。make_moonsで生成した月形の偏ったデータに対してもうまくクラスタリングすることが可能なことを紹介しました。

また、クラスタリング手法で有名なk-means法では、偏ったデータの場合うまくクラスタリングすることができないことを同じくmake_moonsのデータで確認しました。

偏ったデータに対するクラスタリングを考える際には、DBSCANの利用を検討候補にしてみてもらうとよいかと思います。

Note

sklearn.cluster.DBSCANの公式ドキュメントはこちらを参照してください。