Hello Wor.log

IT系大学生4人による備忘録のようなもの

x-meansでクラスタリング【python】

CPPXのXです。

pyclusteringというライブラリを使ってx-meansをやってみたいと思います。 x-meansは、k-meansのkを自動推定しつつクラスタリングしてくれる手法です。

x-meansのアルゴリズムの詳細については、別の方が詳しく説明しています。

qiita.com

環境

  • python 3.5.3
  • pyclustering 0.8.1

pyclusteringはpipでサクッと入ります。

今回使うもの達

import pyclustering
from pyclustering.cluster import xmeans
import numpy as np
import pylab

2次元データ

とりあえずデータを作ります。
データの持ち方は、(データ数, xy) です。

これをクラスタリングします。

data = np.concatenate((
    np.random.uniform(-10, 0,    (100, 2)),
    np.random.uniform(-30, 0,  (100, 2)) + [0, 50],
    np.random.uniform(-30, -20,  (100, 2)),
    np.random.uniform(-60, -30,  (100, 2)) + [-50, 30],
    np.random.uniform(-50, -40,  (100, 2)),
    np.random.uniform(-60, -50,  (100, 2)) + [50, 0],
    np.random.uniform(-70, -60,  (100, 2)),
    np.random.uniform(-80, -70,  (100, 2)) + [-30, 10],
    np.random.uniform(-90, -80,  (100, 2)),
    np.random.uniform(-100, -80, (100, 2)) + [70, 0],
    ), axis=0)

以下のような適当に作ったデータです。 f:id:cppx:20180621004234p:plain

では、クラスタリングします。

初期値は、k-means++による初期値決定を行います。

init_center = pyclustering.cluster.xmeans.kmeans_plusplus_initializer(data, 2).initialize() # 初期値決定 今回は、初期クラスタ2です
xm = pyclustering.cluster.xmeans.xmeans(data, init_center, ccore=False)
xm.process() # クラスタリングします

ccore=Trueにすると、処理にc/c++が使われて早くなるみたいです。

可視化するには、pyclusteringで用意されてる関数を使うと楽です。

clusters = xm.get_clusters()
pyclustering.utils.draw_clusters(data, clusters)

f:id:cppx:20180621085549p:plain

描画にはmatplotlibが使われています。

showさせたくない場合は、display_result=Falseにするといいです。

3次元データ

データを3次元にすると、あとは勝手にやってくれます。

data = np.concatenate((
    np.random.uniform(-10, 0,    (100, 3)),
    np.random.uniform(-20, -10,  (100, 3)) + [0, 50, 0],
    np.random.uniform(-30, -20,  (100, 3)),
    np.random.uniform(-40, -30,  (100, 3)) + [-50, 20, 30],
    np.random.uniform(-50, -40,  (100, 3)),
    np.random.uniform(-60, -50,  (100, 3)) + [50, 0, 100],
    np.random.uniform(-70, -60,  (100, 3)),
    np.random.uniform(-80, -70,  (100, 3)) + [-30, 10, -30],
    np.random.uniform(-90, -80,  (100, 3)) + [0, 0, 50],
    np.random.uniform(-100, -90, (100, 3)) + [70, 0, -30],
    ), axis=0)

f:id:cppx:20180621091233p:plain

これにx-meansかけると、

f:id:cppx:20180621091625p:plain

良さげです。

クラスタリング部分のソースコードは2次元の時に使ったものそのままで大丈夫です。

描画は1~3次元までしか出来ませんが、クラスタリング自体は何次元でも出来ると思います。

irisデータセットの一部にやってみる

可視化する関係上、使うデータを以下の3つに絞ります

  • sepal length (cm)
  • sepal width (cm)
  • petal length (cm)
from sklearn import datasets
iris = datasets.load_iris()
iris.data.shape, iris.target.shape

using = (0, 1, 2)
data = iris.data[..., using]

正解ラベル付きで表示しています。
このデータにx-meansをあててみます。 f:id:cppx:20180621114036p:plain

f:id:cppx:20180621114248p:plain

ほう

今回自分が使ったコードまとめ

おわりです
最後に、今回使ったコードをまとめて貼っておきます。

グラフ表示部分も含めておきました。

2次元

#%% imports
import pyclustering
from pyclustering.cluster import xmeans
import numpy as np
import pylab

#%% create data 2d
data = np.concatenate((
    np.random.uniform(-10, 0,    (100, 2)),
    np.random.uniform(-30, 0,    (100, 2)) + [0, 50],
    np.random.uniform(-30, -20,  (100, 2)),
    np.random.uniform(-60, -30,  (100, 2)) + [-50, 30],
    np.random.uniform(-50, -40,  (100, 2)),
    np.random.uniform(-60, -50,  (100, 2)) + [50, 0],
    np.random.uniform(-70, -60,  (100, 2)),
    np.random.uniform(-80, -70,  (100, 2)) + [-30, 10],
    np.random.uniform(-90, -80,  (100, 2)),
    np.random.uniform(-100, -80, (100, 2)) + [70, 0],
    ), axis=0)

pylab.scatter(data[..., 0], data[..., 1])
pylab.savefig("./data.png")
pylab.show()

#%% clustering
init_center = pyclustering.cluster.xmeans.kmeans_plusplus_initializer(data, 2).initialize()
xm = pyclustering.cluster.xmeans.xmeans(data, init_center, ccore=False)
xm.process()
clusters = xm.get_clusters()
pyclustering.utils.draw_clusters(data, clusters, display_result=False)
pylab.savefig("./data2.png")
pylab.show()

3次元

#%% imports
import pyclustering
from pyclustering.cluster import xmeans
import numpy as np
import pylab
from mpl_toolkits.mplot3d.axes3d import Axes3D
import matplotlib
import matplotlib.pyplot as plt

#%% create data 3d
data = np.concatenate((
    np.random.uniform(-10, 0,    (100, 3)),
    np.random.uniform(-20, -10,  (100, 3)) + [0, 50, 0],
    np.random.uniform(-30, -20,  (100, 3)),
    np.random.uniform(-40, -30,  (100, 3)) + [-50, 20, 30],
    np.random.uniform(-50, -40,  (100, 3)),
    np.random.uniform(-60, -50,  (100, 3)) + [50, 0, 100],
    np.random.uniform(-70, -60,  (100, 3)),
    np.random.uniform(-80, -70,  (100, 3)) + [-30, 10, -30],
    np.random.uniform(-90, -80,  (100, 3)) + [0, 0, 50],
    np.random.uniform(-100, -90, (100, 3)) + [70, 0, -30],
    ), axis=0)

fig = plt.figure()
ax = Axes3D(fig)
ax.scatter3D(data[..., 0], data[..., 1], data[..., 2])
pylab.savefig("./data.png")
plt.show()

#%% clustering
init_center = pyclustering.cluster.xmeans.kmeans_plusplus_initializer(data, 2).initialize()
xm = pyclustering.cluster.xmeans.xmeans(data, init_center, ccore=False)
xm.process()
clusters = xm.get_clusters()
pyclustering.utils.draw_clusters(data, clusters, display_result=False)
pylab.savefig("./data2.png")
pylab.show()

iris

#%% imports
import pyclustering
from pyclustering.cluster import xmeans
import numpy as np
import pylab
from mpl_toolkits.mplot3d.axes3d import Axes3D

#%% load data
from sklearn import datasets
iris = datasets.load_iris()
iris.data.shape, iris.target.shape

#%% plot iris data
using = (0, 1, 2)
iris.feature_names
data = iris.data[..., using]
target = np.concatenate([iris.target[np.where(x == iris.target)] for x in using])

fig = pylab.figure()
ax = Axes3D(fig)
ax.scatter3D(data[..., 0], data[..., 1], data[..., 2], c=iris.target)
pylab.savefig("./data.png")
pylab.show()

#%% clustering 3 data
init_center = pyclustering.cluster.xmeans.kmeans_plusplus_initializer(data, 2).initialize()
xm = pyclustering.cluster.xmeans.xmeans(data, init_center, ccore=False)
xm.process()
clusters = xm.get_clusters()
print(len(clusters))
pyclustering.utils.draw_clusters(data, clusters, display_result=False)
pylab.savefig("./data2.png")
pylab.show()