scikit-learn

【scikit-learn】KMeansでk-means法によるクラスタリングをする方法

【scikit-learn】KMeansでk-means法によるクラスタリングをする方法
naoki-hn

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

k-means 法によるクラスタリング

k-means 法とは、教師なし学習で代表的なクラスタリングの中でも有名な手法の 1 つです。分類アルゴリズムの k-近傍法とは異なるため注意しましょう。

k-means 法のアルゴリズムの手順概要は以下のようになります。

  1. データの中からk個のデータ点を任意に抽出して、初期値のセントロイドとして設定する。その後に、以下の 2、3 のステップを反復する。
  2. 全てのデータ点を最も近いセントロイドにそれぞれ割り振る。
  3. 各 k 個のセントロイドに割り振られたデータの重心を計算して、その重心を新しいセントロイドとして更新する。

ここでセントロイドと言っているのは、各クラスタの中心の事です。

k-means 法では、SSE(Sum of Squared Errors)というクラスタ内の誤差平方和を用いて、この SSE を最小化するようにセントロイドが選ばれます。また、k-means 法は、クラスタ数を事前に指定しないとクラスタリングできないことも特徴です。

k-means 法によるクラスタリングは、Python の機械学習ライブラリである scikit-learn にて KMeans として実装がされています。

この記事では、KMeans を使ったクラスタリング方法の実装例を紹介します。また、クラスタ数を決める方法の 1 つであるエルボー法についても説明します。

k-近傍法については「k近傍法(k-NN)を用いたデータ分類方法」を参考にしてください。

KMeans を使ったクラスタリング

k-menas 法の使い方(sklearn.cluster.KMeans

実装例

scikit-learn の make_blogs でクラスタリング用のデータを用意し、KMeans を使ってk-means 法によるクラスタリングをする方法について紹介します。

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


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

    # ===== データの生成
    k = 5
    data, label = make_blobs(n_samples=500, n_features=2, centers=k, cluster_std=1.0)

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

    # ===== SSE値を出力
    print(f"SSE: {km.inertia_:.2f}")

    # ===== クラスタリング結果を描画する
    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()
【実行結果】
SSE: 894.48
k-means クラスタリング

実装内容の解説

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

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

from sklearn.cluster import KMeans

k-means クラスタリングを使用するには、sklearn.cluster から KMeans をインポートします。他にも NumPy 等インポートしていますが説明は省略します。

データセットの準備

    np.random.seed(1)

    # ===== データの生成
    k = 5
    data, label = make_blobs(n_samples=500, n_features=2, centers=k, cluster_std=1.0)

データは、make_blobs を使用して生成します。引数として指定しているのは以下の項目です。

  • n_sample:データの点数
  • n_features:データの次元数
  • centers:クラスタの数
  • cluster_std:各クラスタの標準偏差

今回は、5 つのクラスタを作成しています。また、教師なし学習のため、label の方は使用していません。乱数シードは、np.random.seed で設定していますが、make_blobsrandom_state 引数で指定することも可能です。

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

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

上記の部分で k-means クラスタリングを実行しています。n_clusters でクラスタ数を指定し、クラスタリングは fit_predict メソッドを使って実行します。

SSE(誤差平方和)の取得

    # ===== SSE値を出力
    print(f"SSE: {km.inertia_:.2f}")

計算された SSE(誤差平方和)については inertia_ で取得できます。

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

    # ===== クラスタリング結果を描画する
    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()

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

k-means クラスタリング

結果を再掲しますが、5 クラスのデータに分類できていることが分かります。

エルボー法によるクラスタ数の決定

k-means 法によるクラスタリングでは、実行前にクラスタ数を決めて指定する必要があります。上記例では、方法の説明のために分かりやすいように 5 つのクラスタのデータセットを作り、そのデータセットに対して k=5 で k-means クラスタリングを実行したため、きれいにクラスタリングができていました。

しかし、実際の適用場面では、データがいくつのクラスタになるかは事前に分かりません。では、k の数をどう決めればよいでしょうか。

クラスタ数を決めるときに参考になる手法としてエルボー法という方法があります。エルボー法では、k-means に指定するクラスタ数の数を増やしていったときに SSE がどのように変化するかをプロットし、その結果からクラスタ数を決定する方法です。

クラスタ数を増やしていって SSE をプロットするとグラフが、かくっと曲がって変化が少なくなる部分が出てきます。エルボー法では、この時のクラスタ数を最適とします。なぜ「エルボー」というかというと SSE のプロット形状が肘が曲がっているように見えるためです。

では、エルボー法でクラスタ数を調べてみるサンプルプログラムを見てみましょう。

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


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

    # ===== データの生成
    k = 5
    data, label = make_blobs(n_samples=500, n_features=2, centers=k, cluster_std=1.0)

    # ===== エルボー法
    sse = []
    for k in range(1, 11):
        km = KMeans(n_clusters=k)
        km.fit(data)
        sse.append(km.inertia_)

    # ===== SSE値をプロットする
    plt.plot(range(1, 11), sse, "o-")
    plt.title("elbow method")
    plt.xlabel("number of clusters")
    plt.ylabel("sse")
    plt.show()


if __name__ == "__main__":
    main()
エルボー法 SSE

上記では、k を 1 ~ 10 まで変えつつ、KMeans を使った k-means クラスタリングを実行しています。そして、図は各 k における SSE の値をリストに蓄積してグラフにプロットしたものになります。

この結果を見るとクラスタ数が 5 のところまでは降下が大きいのに対して 5 以降については緩やかになっているように見えます。このため、k の適切な値は 5 ではないかと予想できます。これがエルボー法での考え方です。

今回は、分かりやすい分類データを使っているため、きれいなプロット図ですが、現実の問題に対しては、これほどきれいにならない場合がほとんどかと思います。

まとめ

Python の機械学習ライブラリである sciki-learn の KMeans を使って k-means 法によるクラスタリングを行う方法を解説してきました。また、k-means にて指定するクラスタ数を決める 1 つの方法であるエルボー法についても紹介しています。

k-means 法は、教師なし学習で代表的なクラスタリングの中でも有名な手法です。scikit-learn の KMeans の使い方も簡単なため、色々な例で試してみてください。

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

ソースコード

上記で紹介しているソースコードについては GitHub にて公開しています。参考にしていただければと思います。

あわせて読みたい
【Python Tech】プログラミングガイド
【Python Tech】プログラミングガイド
ABOUT ME
ホッシー
ホッシー
システムエンジニア
はじめまして。当サイトをご覧いただきありがとうございます。 私は製造業のメーカーで、DX推進や業務システムの設計・開発・導入を担当しているシステムエンジニアです。これまでに転職も経験しており、以前は大手電機メーカーでシステム開発に携わっていました。

プログラミング言語はこれまでC、C++、JAVA等を扱ってきましたが、最近では特に機械学習等の分析でも注目されているPythonについてとても興味をもって取り組んでいます。これまでの経験をもとに、Pythonに興味を持つ方のお役に立てるような情報を発信していきたいと思います。どうぞよろしくお願いいたします。

※キャラクターデザイン:ゼイルン様
記事URLをコピーしました