k-meansよりもちょっとイケてるk-means++

  • 7
    いいね
  • 0
    コメント

本記事では,以下のような特徴を持ったデータを分けることを行いたいと思います.
k-meansをはじめとするクラスタリングでは教師なしの学習(分類)なので,事前にデータの形を見れるということは想定していません.
ですから現実ではクラスタの数を変えていきながら,関数f最小化するを分類を目指してクラスタ数を変更するということになると思います.
※今回はクラスタ数(セントロイド数)を9個としています。

bokeh_plot.png

一応数式で表すと以下のようになります.

それぞれ,Cjがクラスタ,xiがベクトル(データ),mjがセントロイド(クラスタ重心)を表しています.

普通のk-meansでやると以下のような感じで見るからに無様な結果になっています.
これは初期セントロイドを乱数で割り当ててるために,近い位置にセントロイドが置かれた場合にこういう感じになってしまいます.
bokeh_plot (2).png

これを解決する簡単な手法の一つにk-means++という方法があります.
簡単に言えば.複数のセントロイドが近くの位置にならないように初期化するというだけです.

詳しい説明はwikipediaに丸投げします 笑

ソースコード

k-means++.py
from sklearn.cluster import KMeans
from bokeh.plotting import figure, show #グラフの描画には注目されてるbokehを使う.
from bokeh.io import output_notebook
import numpy as np

data = np.loadtxt('./data.txt', delimiter=' ')

# クラスタ, kmeans++で初期化, k-means++で初期クラスタを設定,異なるセントロイドを用いたアルゴリズムの実行回数,最大イテレーション数, 相対許容誤差, 乱数生成器の状態
km = KMeans(n_clusters=9, init='k-means++', n_init=10, max_iter=300, tol=1e-04, random_state=0)
#初期クラスタをランダムで設定する普通のk-means法は以下のようにする.
# km = KMeans(n_clusters=9, init='random', n_init=10, max_iter=300, tol=1e-04, random_state=0)
y_km = km.fit_predict(data4)

# jupyter notebook内にグラフを表示する
output_notebook()

# グラフの設定
p=figure()
p.scatter(data4[y_km==0, 0], data4[y_km==0, 1], color='red')
p.scatter(data4[y_km==1, 0], data4[y_km==1, 1], color='blue')
p.scatter(data4[y_km==2, 0], data4[y_km==2, 1], color='green')
p.scatter(data4[y_km==3, 0], data4[y_km==3, 1], color='pink')
p.scatter(data4[y_km==4, 0], data4[y_km==4, 1], color='gray')
p.scatter(data4[y_km==5, 0], data4[y_km==5, 1], color='purple')
p.scatter(data4[y_km==6, 0], data4[y_km==6, 1], color='yellow')
p.scatter(data4[y_km==7, 0], data4[y_km==7, 1], color="#8f5555")
p.scatter(data4[y_km==8, 0], data4[y_km==8, 1], color='black')
p.scatter(km.cluster_centers_[:, 0], km.cluster_centers_[: ,1], color='orange', marker="square")

# 図の出力
show(p)

data.txtは以下のURLからダウンロードしてください.

k-means++でセントロイドを初期化した結果

bokeh_plot (1).png

綺麗に分類されました.