#動機
k-means法では最初にクラスタ数を決めなければいけないが、x-means法なら自動的に決めてくれる(最適なクラスタ数かどうかはわからないが)。そこでpyclusteringのxmeansを見つけたが使い方がsklearnのスタイルと違ったため使いづらかった。そこで今回はpyclusteringのxmeans.fit
についてsklearn風にラッパーしたいと思う。
#問題点
sklearnのk-meansとpyclusteringのx-meansの大きな違いはskleranでいうlabel_
の配列の返し方が違うところだ。例えば標本として samples = [a,b,c,d]
があり(a,b,c,d) = (0,1,0,1)
でクラスタリングされたとする。
skleranのlabel_
は[0,1,0,1]と標本配列と同じ順番にクラスタ番号の配列を返す。
pyclusteringでいうところのlabel_
(正確にはxmeans.xmeans().getcluster()
)は[[0,2],[1,3]]
と標本配列のインデックスがクラスタ番号順に分類され、その配列を返す。
(国語力が足りない....)
今回はそれを解決する。
#コード
import pyclustering
from pyclustering.cluster import xmeans
import numpy as np
class XMeans:
def fit(self,features):
'''pyclusteringのxmeansで計算'''
initializer = xmeans.kmeans_plusplus_initializer(data=features,amount_centers=2)
initial_centers = initializer.initialize()
xm = xmeans.xmeans(data=features,initial_centers=initial_centers)
xm.process()
"""
分類が出力される
しかしこの出力の仕方がscikit-learnとは違うので厄介
"""
clusters = xm.get_clusters()
'''一次元配列flat_labelを用意'''
flat_label = np.array([])
'''sklearnでいうlabel_の大きさを調べる'''
for cluster in clusters:
flat_label = np.append(flat_label,cluster)
'''正規のlabelを代入するための配列を確保'''
labels = np.zeros((1,flat_label.size))
'''
pyclusteringのclustersはクラスター数次元配列があり、標本の名前がクラスターに分類され配列として返す。
一方でsklearnのlabel_は標本と同様の順番に、その標本が属するクラスターの番号を配列で返す。
下記のコードはその変換を行っている
'''
for n,n_th_cluster in enumerate(clusters):
for img_num in n_th_cluster:
labels[0][img_num] = n
'''このままのラベルだと[[a........z]]の二重括弧になる。
それはsklearnの仕様に沿わない。[a........z]の一重括弧にする。
'''
self.labels_ = labels[0]
return self
2020/05/30 コードを一部修正
@physicalcottonさんのご指摘によりコードを一部修正しました。@physicalcottonさん、ご指摘ありがとうございます。
#まとめ
個人的にこのコードはまだまだ改善の余地があると思っている。もしよければ改善点を申し付けていただいたらありがたい。