【AI・機械学習】k平均法(k-menas)によるモデル構築を解説|sckit-learn活用の教師なしクラスタリング

こんにちは、Kosei(@kay_diacc2)です!

機械学習の教師なし学習であるクラスタリング分析実施にあたり、本記事では「k平均法(k-means法)の概要とプログラミング手法を知りたい」という要望にお答えします。記事前半ではk平均法の原理や評価方法を解説し、後半ではsckit-learnを活用したpythonプログラミング手法を解説します。

目次

クラスタリングとは

クラスタリングとは、機械学習の教師なし学習に該当するもので、類似するサンプルデータを部分集合(クラスタ)として分割することを指します。このように、データから隠れた構造を見つけ出すことに役立つクラスタリングは、マーケティング活動におけるセグメント分析やレコメンドエンジンのアルゴリズム等に広く利用されています。

クラスタリングの用途例

  • 様々な映画・音楽・書籍を同じグループにまとめる
  • 趣味・嗜好が同じ顧客別にグループ分けする

k平均法(k-means algorithm)とは

k平均法(k-means法)とは、非階層的なクラスタリングに該当する手法です。非階層的なクラスタリングとは、サンプルデータをいくつのクラスターに分けるか事前に指定し、指定したクラスター数に基づきサンプルを分割するという方法です。上図の場合、3つのクラスターに分割したと言えます。

k平均法は、実装が容易であり他のクラスタリング手法と比較しても計算効率が優れている、データ容量の大小問わず広く利用できるというメリットがあります。一方で、階層的クラスタリングと異なり、最適なクラスター数を導き出すにはクラスター数を人為的に探索・決定する必要があるのが課題です。

データ容量が比較的小さいサンプルには階層クラスタリングが採用され、ビッグデータなど容量が大きいサンプルにはk平均法のような非階層的クラスタリングが採用される傾向があります。

k平均法を用いたクラスター生成までの流れ

k平均法に基づくクラスタリングでは、具体的にどのようにサンプルが分割され、クラスターが生成されるのでしょうか?以下クラスター生成までの流れを直感的に理解してみましょう!

用語 意味
セントロイド(Centroid) サンプルデータが連続的な場合において、類似する「中心点」を指す
メドイド(Medoid) サンプルデータがカテゴリー値の場合において、最も「代表的」または「頻度が高い」点を指す

クラスタリングの評価指標

機械学習における教師なし学習は、教師あり学習と異なり、明確な答えが用意されていないという課題があります。そのため、クラスタリング性能を定量的に評価するには、何か指標を用いて地道に比較することが大切です。

エルボー法を用いた最適なクラスター数の推定

最適なクラスタ数を求める方法としては、「エルボー法」がよく用いられます。エルボー法とは、クラスタ内誤差平均和(SSE)という指標に基づき、最適なクラスタ数を導出する方法です。SSEとは、各クラスタのセントロイドから各サンプルまでの距離の総和であり、下記のような規則性を有します。

上記をグラフに表すと下記のようなイメージになります。

上記グラフを用いたエルボー法では、SSE値が急激に減少している部分において、SSE値が最も小さい点が最適なクラスター数であると判断します。(上図例だとクラスター数=4が最適)

シルエット図を用いたクラスタリング性能の評価

クラスタリングの性能を評価する他の指標として、シルエット分析があります。シルエット分析とは下記の基準に基づきクラスタリング性能を評価するもので、k平均法意外のクラスタリングアルゴリズムにも適用できる分析手法です。

  • クラスタ内のサンプルが密にグループ化されている(凝集度が高い)ほど良い
  • 異なるクラスタは距離が離れているほど良い

上記具体的なクラスタリング性能評価は、シルエット係数(silhouette coefficient)に基づき実施されます。

s(i) = b(i) a(i) max{ b(i) a(i) }

  • a(i):凝集度(同一クラスタのサンプル(i)と他の全サンプルとの平均距離)
  • b(i):乖離度(サンプル(i)から最も近くにあるクラスタ内全サンプルとの平均距離)
  • s(i):シルエット係数

シルエット係数は[-1:1]の範囲を取り、シルエット係数が1に近づくほどクラスタリング性能が良いと判断できます。また、下記グラフのように可視化することで性能の優劣が判断しやすくなります。

Pythonプログラミングによるモデル構築実践

k平均法を用いたクラスタリングモデルを構築するにあたり、ここからは実際にpythonによるプログラミングを実践します。モデル構築は下記の手順で実施します。

  1. データの準備・理解
  2. エルボー法を用いた最適なクラスター数の推定
  3. クラスタリングモデル作成
  4. シルエット図を用いたモデル性能評価

データの準備・理解

本記事では「顧客属性別の居住マンション価格に関するデータセット」を用いており、顧客の年収とマンションにかかる費用で顧客をグループ分けすることします。

import pandas as pd
df = pd.read_csv("sample_data.csv")

#クラスタリング軸(年収 vs マンション費用)
X = df.iloc[:, [3, 4]].values

#出力
print(df.tail())

表:sample_data.csvのデータ例

性別 年齢 職業 年収[万円] マンション費用[万/月]
32 商社 700 12
26 公務員 350 4

エルボー法を用いた最適なクラスター数の指定

エルボー法を用いて最適なクラスター数を推察します。下記のように記述しましょう。

from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
from matplotlib import rcParams
rcParams['font.family'] = 'sans-serif'
rcParams['font.sans-serif'] = 'Hiragino Maru Gothic Pro'

#クラスタリング軸( 年収 vs マンション費用 )
X = df.iloc[:, [3, 4]].values

#エルボー法
max_cluster = 15
SSE = []
for i in range(1,max_cluster):
    #インスタンス
    kmeans = KMeans(n_clusters = i,      #クラスタの個数
                    init = 'k-means++',  #k平均++法によりクラスタ中心を選択
                    n_init= 5,           #異なるセントロイドの初期値を用いたk平均法アルゴリズム実行回数
                    max_iter=350,        #k平均法アルゴリズム内部の最大イテレーション(サイクル繰り返し)回数
                    tol=1e-04,           #収束と判定できる相対的許容誤差
                    random_state = 42    #セントロイド初期化に際して、用いる乱数生成器の設定
                   ) 
    #演算
    kmeans.fit(X)
    #wcss値に変換&リスト格納
    SSE.append(kmeans.inertia_)
    
#可視化
plt.plot(range(1,max_cluster), SSE)
plt.title('エルボー法による最適なクラスター数の調査')
plt.xlabel('クラスター数[個]')
plt.ylabel('SSE')
plt.show()

上記の場合、最適なクラスターの個数は3がだと推察できます。

クラスタリングモデル作成

エルボー法で算出したクラスターの個数をもとに、k-meansアルゴリズムに基づくクラスタリングモデルを作成します。下記のように記述してみましょう。

import numpy as np
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
from matplotlib import rcParams
rcParams['font.family'] = 'sans-serif'
rcParams['font.sans-serif'] = 'Hiragino Maru Gothic Pro'
from matplotlib import cm

#クラスタリング軸( 年収 vs マンション費用 )
X = df.iloc[:, [3, 4]].values

#k-meansインスタンス
kmeans = KMeans(n_clusters = 3,      #クラスタの個数
                init = 'k-means++',  #k平均++法によりクラスタ中心を選択
                n_init= 5,           #異なるセントロイドの初期値を用いたk平均法アルゴリズム実行回数
                max_iter=350,        #k平均法アルゴリズム内部の最大サイクル繰り返し回数
                tol=1e-04,           #収束判定する相対的許容誤差
                random_state = 42    #セントロイド初期化に際して、用いる乱数シードを設定
               ) 

#演算
y_kmeans = kmeans.fit_predict(X)

#配列情報
cluster_labels = np.unique(y_kmeans)               #一意なクラスター要素
n_clusters = cluster_labels.shape[0]               #配列の長さ

#グラフ可視化
for i in range(len(cluster_labels)):
    color = cm.jet(float(i) / n_clusters)
    plt.scatter(X[y_kmeans == i, 0], X[y_kmeans == i, 1], s = 100, c = color, label = 'Cluster'+str(i))

plt.scatter(kmeans.cluster_centers_[:, 0], kmeans.cluster_centers_[:, 1], s = 100, c = 'red', label = 'Centroids')
plt.title('顧客属性クラスター')
plt.xlabel('年収[万円]')
plt.ylabel('マンション費用[万円/月]')
plt.legend()
plt.show()

下記条件を有するインスタンスに基づき、k-meansモデルを構築しています。

from sklearn.cluster import KMeans
#k-meansインスタンス
kmeans = KMeans(n_clusters = 3,      #クラスタの個数
                init = 'k-means++',  #k平均++法によりクラスタ中心を選択
                n_init= 5,           #異なるセントロイドの初期値を用いたk平均法アルゴリズム実行回数
                max_iter=350,        #k平均法アルゴリズム内部の最大サイクル繰り返し回数
                tol=1e-04,           #収束判定する相対的許容誤差
                random_state = 42    #セントロイド初期化に際して、用いる乱数シードを設定
               ) 

sklearn.cluster.KMeansインスタンスの引数には下記を与えることができます。

引数名 概要 デフォルト
n_clusters クラスタの個数 8
init 初期化方法(k-means++, random, ndarray) k-means++
n_init 異なるセントロイドの初期値を用いたk平均法アルゴリズム実行回数 10
max_iter k平均法アルゴリズム内部の最大サイクル繰り返し回数 300
tol 収束判定する相対的許容誤差 0.0001
precompute_distance 距離(バラツキ)のを事前計算するか(auto,True,False) auto
verbose 1を指定し分析詳細を表示(1,0) 0
random_state セントロイド初期化に際して、用いる乱数シードを設定 0

インスタンスのパラメーターは下記のように確認することが可能です。

kmeans.get_params

# 出力結果
# <bound method BaseEstimator.get_params of KMeans(algorithm='auto', copy_x=True, init='k-means++', max_iter=350,
#        n_clusters=3, n_init=5, n_jobs=None, precompute_distances='auto',
#        random_state=42, tol=0.0001, verbose=0)>

シルエット図を用いたモデル性能評価

最後にシルエット分析を用いてクラスタリングモデルの性能評価を実施します。下記のように記述してみましょう。

import numpy as np
from matplotlib import cm
from sklearn.metrics import silhouette_samples

#配列情報
cluster_labels = np.unique(y_kmeans)               #一意なクラスター要素
n_clusters = cluster_labels.shape[0]               #配列の長さ

#シルエット係数の計算
silhouette = silhouette_samples(X,y_kmeans, metric="euclidean")
axis_y_btm, axis_y_up = 0, 0
y_list = []

#シルエット係数・グラフデータ計算
for i,label in enumerate(cluster_labels):
    wd_silhouette = silhouette[y_kmeans == label]
    wd_silhouette.sort()
    axis_y_up += len(wd_silhouette)
    color = cm.jet(float(i) / n_clusters)                   #色
    
    #水平棒グラフ
    plt.barh(                                               
             range(axis_y_btm, axis_y_up),                  #底辺の範囲
             wd_silhouette,                                 #棒の幅
             height = 1.0,                                  #棒の高さ
             edgecolor = "none",                            #棒端の色
             color = color)                                 #棒の色                               
    
    #クラスラベルの表示位置追加
    y_list.append((axis_y_btm + axis_y_up) /2)  
    #底辺の値に棒の幅を追加
    axis_y_btm += len(wd_silhouette)                         
    
#シルエット係数の平均値
silhouette_mean = np.mean(silhouette) 
#可視化
plt.axvline(silhouette_mean, c="r", linestyle="--")         
plt.yticks(y_list, cluster_labels+1)
plt.ylabel("クラスター")
plt.xlabel("シルエット係数")
plt.tight_layout()
plt.show()

シルエット係数が1であれば性能が良いクラスタリングと言えますが、今回の例では係数が0.6~0.7付近であることから、あまり性能が良いとは言えません。このような結果が出た場合、クラスタリング数を変更等行うことで性能比較を繰り返し、最適なモデルを探求するのが良いでしょう。

クラスター分析まとめ

最後までご覧いただきありがとうございました。クラスタリングは教師なし学習の代表的手法であり、データにある隠れた規則性を見出すのに非常に有効な手法です。

以下本日の学習ポイントまとめです。

・クラスタリングとは、データにある隠れた規則性を見出す手法
・クラスタリングには「階層的クラスタリング」と「非階層的クラスタリング」がある。

最後に、Pythonを用いたクラスター分析についてもっと学習したい方向けにおすすめ教材を紹介します。興味のある方は是非ご覧下さい。

【初学者向け】データサイエンス・人工知能(AI)開発のおすすめ学習方法も解説してます。是非ご覧ください。

最後に

この記事が気に入ったら
フォローしてね!

本記事をシェア!
URLをコピーする
URLをコピーしました!
目次
閉じる