Python × AI - スクリープロット(次元削減数を探索)

PCAは、教師あり学習の説明変数としての用途もあります。

その際には、次元を減らしつつも元の情報をなるべく保持しているPCまで使う必要があります。

今回は、有効なPC数を探索していきます。

ワインデータの取得

アイリスデータより次元数の多いワインデータを使用します。

ワインデータは列名が入っていないので、列名を定義しています。(2行目)

[Google Colaboratory]

1
2
3
4
df_wine=pd.read_csv("https://archive.ics.uci.edu/ml/machine-learning-databases/wine/wine.data", header=None)
df_wine.columns = ["class", "Alcohol", "Malic acid", "Ash", "Alcalinity of ash","Magnesium", "Total phenols", "Flavanoids", "Nonflavanoid phenols","Proanthocyanins", "Color intensity", "Hue","OD280/OD315 of diluted wines", "Proline"]
display(df_wine.shape)
display(df_wine.head())

[実行結果]

正解データが入っているため、14次元サンプル数が178件のデータになります。

ワインデータの可視化

取得したワインデータを散布図行列で可視化します。

[Google Colaboratory]

1
2
3
from pandas import plotting
plotting.scatter_matrix(df_wine.iloc[:, 1:], figsize=(8, 8), c=list(df_wine.iloc[:, 0]), alpha=0.5)
plt.show()

[実行結果]

次元数が多いため、とても判断が難しくなっています。

だいたい3~4種類に分かれているような気がしなくもありません。

PCA

PCAを実行します。

[Google Colaboratory]

1
2
3
4
5
6
7
8
9
10
11
12
13
from sklearn.decomposition import PCA
from sklearn import preprocessing
import numpy as np
sc=preprocessing.StandardScaler()
X = df_wine.iloc[:, 1:]
X_norm=sc.fit_transform(X)

pca = PCA(random_state=0)
X_pc = pca.fit_transform(X_norm)
df_pca = pd.DataFrame(X_pc, columns=["PC{}".format(i + 1) for i in range(len(X_pc[0]))])
print("主成分の数: ", pca.n_components_)
print("保たれている情報: ", round(np.sum(pca.explained_variance_ratio_),2))
display(df_pca.head())

[実行結果]

主成分の数がPC1からPC13の13個あります。

パラメータのn_componentsを指定しない場合、主成分は元データの次元数と一致します。

全次元を対象にしたので保たれている情報は1.0(100%)になります。

固有値

固有値を確認して、PC1からどこまでが有効な主成分かを探索してみましょう。

[Google Colaboratory]

1
pd.DataFrame(np.round(pca.explained_variance_, 2), index=["PC{}".format(x + 1) for x in range(len(df_pca.columns))], columns=["固有値"])

[実行結果]

固有値(explained_variance)は、主成分の分散のことで主成分の情報量の大きさを表します。

PC1がもっとも大きく、次第に小さくなっていきます。

標準化している場合には、固有値が1.0以上のものを使うというのがもっともシンプルな判断基準となります。

今回の結果ですと、PC3までを使うことになります。

スクリープロットで可視化

次にスクリープロットを確認します。

スクリープロットは、固有値を最大から最小まで降順でプロットしたグラフのことで、崖(スクリー:scree)のような形になります。

固有値からスクリープロットを作成(2行目)し、グラフ表示するソースは以下の通りです。

固有値1.0の基準線も合わせて表示しています。(1,3行目)

[Google Colaboratory]

1
2
3
4
5
6
7
8
line = np.ones(14)
plt.plot(np.append(np.nan, pca.explained_variance_), "s-")
plt.plot(line, "s-")
plt.xlabel("PC")
plt.ylabel("explained_variance")
plt.xticks( np.arange(1, 14, 1))
plt.grid()
plt.show()

[実行結果]

固有値が、ある段階から急に小さな値となって以降は安定する箇所までを利用することが望ましいとされています。

上記のグラフだとPC7あたりかと思いますが、使用用途に応じて±2程度で調整する必要があります。

Python × AI - 主成分と元データの相関(PCA)

前回作成した主成分を解析します。

PCAの結果

PCAの結果から取得できる値は次の通りです。

  • 固有ベクトル : components_
    PCAでデータのばらつきが大きい方向に軸を取り直した結果のベクトル。
    各主成分と元データとの相関関係(-1~1)を意味し、元のデータと主成分の影響度合いを表す。
  • 主成分得点 : explained_variance
    固有ベクトルと元データをかけ合わせた値。
     主成分得点 = 元データ × 固有ベクトル
  • 固有値 : explained_variance_
    固有ベクトルの方向に沿ったデータの分散の大きさ。
    固有値が大きい固有ベクトルほど、データの分散をよく説明しており、データの重要な特徴を捉えている。
    データを標準化している場合、各PCは1以上あれば元データより情報をもっていることになり、4次元データであれば全ての合計は4になる。
  • 寄与率 : explained_variance_ratio_
    固有値から算出した、データ特徴の捉え度合い。
     寄与率 = 固有値 ÷ 固有値の合計

相関図

元データとの関係を固有ベクトル(components)から確認します。

固有ベクトルのヒートマップを表示します。(4~12行目)

[Google Colaboratory]

1
2
3
4
5
6
7
8
9
10
11
12
import seaborn as sns
fig = plt.figure(figsize=(8,6))
ax = fig.add_subplot(111)
sns.heatmap(pca.components_,
cmap="Blues",
annot=True,
annot_kws={"size": 14},
fmt=".2f",
xticklabels=["SepalLength", "SepalWidth", "PetalLength", "PetalLength"],
yticklabels=["PC1", "PC2", "PC3", "PC4"],
ax=ax)
plt.show()

[実行結果]

上図は、各主成分(縦軸)と元データ(横軸)との相関関係を表しています。

PC1をみると、SepalLength、PetalLength、PetalWidthの3つが平均として大きな値となっています。

PC2については、SepalWidthが強く影響しています。

このように主成分がどんな内容の軸になったのかは、PCAの結果を見て判断する必要があります。

Python × AI - 主成分分析(PCA)

主成分分析(PCA:Principal Component Analysis)は、多次元データのもつ情報をできるだけ損なわずに低次元とする方法です。

次元削減で最も簡単な方法であり、広い分野で使われています。

アイリスデータの読み込み

まずアイリスデータを読み込みます。

結果の確認用にtarget_nameに正解の花の名称を追加しています。(5~8行目)

[Google Colaboratory]

1
2
3
4
5
6
7
8
9
import pandas as pd
from sklearn.datasets import load_iris
iris = load_iris()
df=pd.DataFrame(iris.data, columns=iris.feature_names)
df["target"] = iris.target
df.loc[df["target"]==0, "target_name"] = "setosa"
df.loc[df["target"]==1, "target_name"] = "versicolor"
df.loc[df["target"]==2, "target_name"] = "virginica"
df.head()

[実行結果]

アイリスデータの散布図行列

読み込んだアイリスデータを散布図行列で可視化します。

hueパラメータに名称”target_name”を設定することで色をつけています。(2行目)

[Google Colaboratory]

1
2
import seaborn as sns
sns.pairplot(df, vars=df.columns[:4], hue="target_name")

[実行結果]

品種ごとに色分けされていて分類されていることは把握できますが、次元が多いため解釈するのが大変です。

アイリスの3次元立体図

花の品種ごとにpetal_width以外の情報を取得します。(5~6行目)

その後、3次元での可視化を行います。(7~12行目)

[Google Colaboratory]

1
2
3
4
5
6
7
8
9
10
11
12
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure(figsize=(8,6))
ax = fig.add_subplot(1, 1, 1, projection="3d")
for c in df["target_name"].unique():
ax.scatter(df.iloc[:, 0][df["target_name"]==c], df.iloc[:, 1][df["target_name"]==c] , df.iloc[:, 2][df["target_name"]==c], label=c)
ax.set_title("iris 3D")
ax.set_xlabel("sepal_length")
ax.set_ylabel("sepal_width")
ax.set_zlabel("petal_length")
ax.legend(loc=2, title="legend", shadow=True)
plt.show()

[実行結果]

3品種に分かれているように見えますが、petal_widthの情報は全く無視してしまっています。

この情報が特徴量のある重要なデータだったという可能性もあります。

PCAを使用すれば、この4次元データを2次元データで表現することが可能になります。

PCA実行

PCAを実行し(3~4行目)、結果である主成分得点を表示します(5~8行目)。

[Google Colaboratory]

1
2
3
4
5
6
7
8
from sklearn.decomposition import PCA
import numpy as np
pca = PCA(random_state=0)
X_pc = pca.fit_transform(df.iloc[:, 0:4])
df_pca = pd.DataFrame(X_pc, columns=["PC{}".format(i + 1) for i in range(len(X_pc[0]))])
print("主成分の数: ", pca.n_components_)
print("保たれている情報: ", np.sum(pca.explained_variance_ratio_))
display(df_pca.head())

[実行結果]

横軸が主成分(PC:Principal Component)で、縦軸が各サンプルを表します。

主成分(PC)とは、データを要約(縮小)したあとの新しい合成変数で、第1主成分(PC1)に最も多くの情報が集まっていて第2主成分(PC2)以降にだんだんと情報が小さくなります。

PC1とPC2を可視化

多くの情報が集まっているPC1PC2を可視化します。

[Google Colaboratory]

1
sns.scatterplot(x="PC1", y="PC2", data=df_pca, hue=df["target_name"])

[実行結果]

4次元あったデータを2次元で可視化することができました。

うまく3種類に分類されています。

PCAの用途はいくつかあるのですが、多次元データの特徴を低次元に次元削減し可視化する手段としてとても有効です。

Python × AI - クラスタリング(HDBSCAN)

HDBSCANを使ってクラスタリングを行います。

HDBSCANは、DBSCANを階層型クラスタリングのアルゴリズムに変換したもので、階層DBSCAN(Hierarchical DBSCAN)と呼ばれることもあります。

密度でグループを作成し、そのグループを距離に基づいて順次まとめていきます。

ライブラリのインストールとデータ生成

まずHDBSCANのライブラリをインストールします。(1行目)

2行目以降でデータ生成を行います。

密度の異なる3つの塊データを作成しています。

[Google Colaboratory]

1
2
3
4
5
6
7
8
9
10
!pip install hdbscan 
centers = [[1, 0.5], [2, 2], [1, -1]]
stds = [0.1, 0.4, 0.2]
X = datasets.make_blobs(n_samples=1000, centers=centers, cluster_std=stds, random_state=0)[0]
x = X[:,0]
y = X[:,1]
plt.figure(figsize=(10,7))
plt.scatter(x, y)
plt.suptitle("blob")
plt.show

[実行結果]

クラスタリング

比較のため、HDBSCAN(1~7行目)とDBSCAN(9~16行目)でクラスタリングを行います。

[Google Colaboratory]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
print("\nDBSCAN")
dbscan = cluster.DBSCAN(eps=0.2, min_samples=10, metric="euclidean")
labels = dbscan.fit_predict(X)
df_dbscan = pd.DataFrame(X)
df_dbscan["cluster"] = labels
df_dbscan.columns = ["axis_0","axis_1","cluster"]
display(df_dbscan["cluster"].value_counts().sort_index())

import hdbscan
print("\nHDBSCAN")
hdbscan_ = hdbscan.HDBSCAN()
hdbscan_.fit(X)
df_hdbscan = pd.DataFrame(X)
df_hdbscan["cluster"] = hdbscan_.labels_
df_hdbscan.columns = ["axis_0","axis_1","cluster"]
display(df_hdbscan["cluster"].value_counts().sort_index())

[実行結果]

DBSCANは外れ値(-1)が少しありますが、HDBSCANは3つに分類されています。

クラスタリング結果の可視化

各クラスタリング結果を可視化します。

[Google Colaboratory]

1
2
3
4
5
6
7
plt.figure(figsize=(10,3))
plt.suptitle("dbscan")
sns.scatterplot(x="axis_0", y="axis_1", hue="cluster", data = df_dbscan)

plt.figure(figsize=(10,3))
plt.suptitle("hdbscan")
sns.scatterplot(x="axis_0", y="axis_1", hue="cluster", data = df_hdbscan)

[実行結果]

HDBSCAN(下図)は、塊ごとの密度の違いに対応できるアルゴリズムのため、きちんと3つに分類されています。

DBSCAN(上図)は密度の低い塊はノイズになっているようです。

2つのクラスタリングの使い分けポイントとしては、塊ごとに密度が違うかどうかという点になります。

Python × AI - ノイズ確認(DBSCAN)

ノイズ確認

DBSCANでは、どのクラスタにも所属しないノイズ点(外れ値)を分離できるという特徴があります。

前回実施した塊データのクラスタリングからクラスタごとのデータ数を確認します。

各クラスタのデータ数をカウントして、クラスタ番号でソートします。

[Google Colaboratory]

1
pd.DataFrame(labels)[0].value_counts().sort_index()

[実行結果]

1列目がクラスタ番号で-1~4が付与されています。

2列目は所属クラスタのデータ数です。

ノイズはクラスタ番号が-1が付与されるので、7個のデータがノイズと分類されていることが分かります。

ノイズの可視化

続いてノイズデータの可視化を行います。

[Google Colaboratory]

1
2
3
4
5
6
7
import seaborn as sns
df_dbscan = pd.DataFrame(X)
df_dbscan["cluster"] = labels
df_dbscan.columns = ["axis_0","axis_1","cluster"]
df_dbscan.head()
plt.figure(figsize=(10,3))
sns.scatterplot(x="axis_0", y="axis_1", hue="cluster", data = df_dbscan)

[実行結果]

大きなクラスタから離れている点がクラスタラベルで-1でノイズ点となっています。

ノイズ点はクラスタリングの用途によっては除外しますが、反対に異常値として検知するために注目することもあります。

Python × AI - クラスタリング(DBSCAN)

DBSCAN(Density-Based Spatial Clustering of Applications with Noise)を使って、クラスタリングを行います。

DBSCANは、密度準拠クラスタリングのアルゴリズムを使います。

密接している点を同じグループにまとめ、低密度領域にある点をノイズ(外れ値)と判定します。

各点は自身の半径以内に点がいくつあるかでその領域をクラスタとして判断するため、クラスタ数をあらかじめ決めなくていいという長所があります。

近傍の密度がある閾値を超えている限り、クラスタを成長させ続け、半径以内にない点はノイズになります。

データセットの準備

今回は2種類のデータセットを生成します。

1つ目のデータセットとして塊データを生成し、可視化します。(1~9行目)

2つ目のデータセットとしてムーンデータを生成し、可視化します。(11~19行目)

[Google Colaboratory]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
X = datasets.make_blobs(n_samples=1000, random_state=10, centers=5, cluster_std=1.2)[0]
sc = preprocessing.StandardScaler()
X_norm = sc.fit_transform(X)
x = X_norm[:,0]
y = X_norm[:,1]
plt.figure(figsize=(10,3))
plt.scatter(x,y)
plt.suptitle("blob")
plt.show

X_moon = datasets.make_moons(n_samples=1000, noise=0.05, random_state=0)[0]
sc = preprocessing.StandardScaler()
X_moon_norm = sc.fit_transform(X_moon)
x_moon = X_moon_norm[:,0]
y_moon = X_moon_norm[:,1]
plt.figure(figsize=(10,3))
plt.scatter(x_moon,y_moon)
plt.suptitle("moon")
plt.show

[実行結果]

ムーンデータをクラスタリング

まずk-meansのクラスタリング結果を可視化し(1~7行目)、その後にDBSCANでクラスタリングを行ってから同じく可視化しています(9~14行目)。

DBSCANモデルはcluster.DBSCAN関数で作成しします。(9行目)

[Google Colaboratory]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
km_moon = cluster.KMeans(n_clusters=2)
z_km_moon = km_moon.fit(X_moon_norm)
plt.figure(figsize = (10,3))
plt.scatter(x_moon,y_moon, c=z_km_moon.labels_)
plt.scatter(z_km_moon.cluster_centers_[:,0],z_km_moon.cluster_centers_[:,1],s=250, marker="*",c="red")
plt.suptitle("k-means")
plt.show

dbscan = cluster.DBSCAN(eps=0.2, min_samples=5, metric="euclidean")
labels = dbscan.fit_predict(X_moon_norm)
plt.figure(figsize=(10,3))
plt.scatter(x_moon,y_moon, c=labels)
plt.suptitle("dbscan")
plt.show

[実行結果]

k-meansではうまく分類できていませんが、DBSCANだときちんと分類されています。

塊データをクラスタリング

塊データもk-meansDBSCANでクラスタリングを行ってみます。

[Google Colaboratory]

1
2
3
4
5
6
7
8
9
10
11
12
13
km=cluster.KMeans(n_clusters=5)
z_km=km.fit(X_norm)
plt.figure(figsize=(10,3))
plt.scatter(x,y, c=z_km.labels_)
plt.scatter(z_km.cluster_centers_[:,0],z_km.cluster_centers_[:,1],s=250, marker="*",c="red")
plt.suptitle("k-means")

dbscan = cluster.DBSCAN(eps=0.2, min_samples=5, metric="euclidean")
labels = dbscan.fit_predict(X_norm)
plt.figure(figsize=(10,3))
plt.scatter(x,y, c=labels)
plt.suptitle("dbscan")
plt.show

[実行結果]

今回は両方のアルゴリズムでうまく分類できているようです。

DBSCANは、データの密度を基準とするアルゴリズムで、全データ点はコア点到達可能点ノイズ点に分類されます。

8行目のepsパラメータで決められた半径内にmin_samplesパラメータの値以上の点が集まっていれば、それをコア点であると判断します。

コア点ではないデータでも、近くにあるコア点からeps半径の中に入っているものは到達可能点であると判断します。

そのどちらにもなれなかった点はノイズ点(外れ値)として分類されます。

DBSCANにおいて、epsmin_samplesはとても重要なパラメータだということになります。

DBSCANの総括

DBSCANは球の形状を前提とせず、ノイズ分類もできて、クラスタ数の指定も必要ないクラスタリングになります。

デメリットとしては、全データ点を対象とした反復計算を実施しているため計算コストが高くリアルタイム性が求められるよな場合には不向きです。

またデータが密集しているとパラメータ調整が難しくなるという一面もあります。

Python × AI - クラスタリング(MiniBatchKMeans)

MiniBatchKMeansでのクラスタリングを実行します。

ミニバッチとは部分的にサンプリングされた入力データのことです。

ミニバッチでクラスタリングを行うことにより、計算時間を大幅に短縮することができますが、k-meansと比べると少し精度が落ちることがあります。

MiniBatchKMeansでクラスタリング

データは前回同様にワインの分類データセットを使います。

比較のため、最初にk-meansのクラスタリング結果を可視化し(1~5行目)、その後にMiniBatchKMeansでクラスタリングを行ってから同じく可視化しています(7~14行目)。

MiniBatchKMeansモデルはcluster.MiniBatchKMeans関数で作成し、batch_sizeには100を設定しています。(7行目)

[Google Colaboratory]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
plt.figure(figsize=(10,3))
plt.scatter(x,y, c=z_km.labels_)
plt.scatter(z_km.cluster_centers_[:,0],z_km.cluster_centers_[:,1],s=250, marker="*",c="red")
plt.suptitle("k-means")
plt.show

minikm = cluster.MiniBatchKMeans(n_clusters=3, batch_size=100)
z_minikm=minikm.fit(X_norm)

plt.figure(figsize=(10,3))
plt.scatter(x,y, c=z_minikm.labels_)
plt.scatter(z_minikm.cluster_centers_[:,0],z_minikm.cluster_centers_[:,1],s=250, marker="*",c="red")
plt.suptitle("mini-k-means")
plt.show

[実行結果]

k-meansとMiniBatchKMeansの結果は、ほぼ同じとなりました。

MiniBatchKMeansでは、全データではなくbatch_size分のデータごとにk-meansを実行し、結果を更新する手法です。

データが1万個よりも多い場合はMiniBatchKMeansを使うことが推奨されています。

GMMモデルなどの感度のよいクラスタリングは計算時間がかかってしまいますので、データが多い場合はMiniBatchKMeansの利用を検討しましょう。

Python × AI - クラスタリング(VBGMM)

変分混合ガウスモデル(VBGMM:Variational Bayesian Gaussian Mixture)でのクラスタリングを試してみます。

VBGMMは、クラスタ数が不明な場合に有効な手法です。

複数のガウス分布を仮定して、各データがどのガウス分布に所属するのかを決定してクラスタ分析を行います。

MeanShiftとは違って、ベイズ推定に基づいて確率分布を計算しながらクラスタ数や分布の形状を決定します。

VBGMMでクラスタリング

データは前前前回使用したワインの分類データセットを使います。(前前前回記事を参照)

比較のため、最初にk-meansのクラスタリング結果を可視化し(1~5行目)、その後にGMMでクラスタリングを行ってから同じく可視化しています(7~15行目)。

VBGMMモデルはmixture.BayesianGaussianMixture関数で作成し、クラスタ数の上限としてn_components10を指定しています。(8行目)

[Google Colaboratory]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
plt.figure(figsize=(10,3))
plt.scatter(x,y, c=z_km.labels_)
plt.scatter(z_km.cluster_centers_[:,0],z_km.cluster_centers_[:,1],s=250, marker="*",c="red")
plt.suptitle("k-means")
plt.show

from sklearn import mixture
vbgmm = mixture.BayesianGaussianMixture(n_components=10, random_state=0)
vbgmm=vbgmm.fit(X_norm)
labels=vbgmm.predict(X_norm)

plt.figure(figsize=(10,3))
plt.scatter(x,y, c=labels)
plt.suptitle("vbgmm")
plt.show

[実行結果]

VBGMMで最適なクラスタ数を探す

VBGMMでは、weightsを参照するとクラスタごとの各データ分布を確認することができます。

縦軸がweightsで、横軸がクラスタ番号の棒グラフを作成します。(3行目)

[Google Colaboratory]

1
2
3
4
5
x_tick =np.array([1,2,3,4,5,6,7,8,9,10])
plt.figure(figsize=(10,2))
plt.bar(x_tick, vbgmm.weights_, width=0.7, tick_label=x_tick)
plt.suptitle("vbgmm_weights")
plt.show

[実行結果]

クラスタ数の上限(n_components)を10で実行しましたが、1つも分類されていないクラスタがあります。

クラスタ数の変更

グラフで見ると、だいたい3つ(クラスタ番号1~2と4と7)に分類されているので、n_componentsに3を設定して、もう一度クラスタリングを行います。(1行目)

[Google Colaboratory]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
vbgmm = mixture.BayesianGaussianMixture(n_components=3, random_state=0)
vbgmm=vbgmm.fit(X_norm)
labels=vbgmm.predict(X_norm)

plt.figure(figsize=(10,3))
plt.scatter(x,y, c=labels)
plt.suptitle("vbgmm")
plt.show

x_tick =np.array([1,2,3])
plt.figure(figsize=(10,2))
plt.bar(x_tick, vbgmm.weights_, width=0.7, tick_label=x_tick)
plt.suptitle("vbgmm_weights")
plt.show

[実行結果]

今回実施したように、VBGMMではweightsを確認して低い割合のクラスタがある場合は、n_componentsをさげて再度クラスタリングを行うという手順でクラスタ数を調整することが可能です。

Python × AI - クラスタリング(GMM)

混合ガウスモデル(GMM:Gaussian Mixture Model)でのクラスタリングを試してみます。

GMMは各データが、どのガウス分布に所属している確率が最も高いかを求めてラベリングを行います。

GMMでクラスタリング

データは前前回使用したワインの分類データセットを使います。(前前回記事を参照)

比較のため、最初にk-meansのクラスタリング結果を可視化し(1~5行目)、その後にGMMでクラスタリングを行ってから同じく可視化しています(7~15行目)。

GMMモデルはmixture.GaussianMixture関数で作成し、クラスタ数(n_components)には3を指定しています。(8行目)

[Google Colaboratory]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
plt.figure(figsize=(10,3))
plt.scatter(x, y, c=z_km.labels_)
plt.scatter(z_km.cluster_centers_[:,0], z_km.cluster_centers_[:,1], s=250, marker="*", c="red")
plt.suptitle("k-means")
plt.show

from sklearn import mixture
gmm = mixture.GaussianMixture(n_components=3, covariance_type="full")
z_gmm = gmm.fit(X_norm)
z_gmm = z_gmm.predict(X_norm)

plt.figure(figsize=(10,3))
plt.scatter(x, y, c=z_gmm)
plt.suptitle("gmm")
plt.show

[実行結果]

k-meansGMMでのクラスタリング結果はほとんど同じように見えます。

ただk-meansでは同心円状での分類であり、GMMは傾いた楕円形の分類であるために多少の違いがあるようです。

またGMMではガウス分布を仮定するので、各データがどのクラスタに所属するのかという確率を求めることができます。

Python × AI - クラスタリング(X-means)

今回はX-meansというクラスタリングを試します。

前回試したMeanShiftと同様に、X-meansもクラスタ数を自動で設定してくれます。

X-meansは、k-meansのアルゴリズムに加えて、あるクラスタが正規分布2つで表されるのと1つで表されるのとでどちらが適切かを判定し、2つが適切な場合はクラスタ数を2つに分けるというアルゴリズムになります。

X-meansでクラスタリング

データは前回使用したワインの分類データセットを使います。(前回記事を参照)

まずx-meansライブラリをインストールします。(1行目)

クラスタ数の初期値として2を指定(5行目)していますが、適切なクラスタ数でクラスタリングを実施してくれます。

kmaxパラメータには最大クラスタ数を指定しています。(6行目)

最後にprocess関数をコールしてX-meansでクラスタリングを実行します。(7行目)

[Google Colaboratory]

1
2
3
4
5
6
7
!pip install pyclustering

from pyclustering.cluster.xmeans import xmeans
from pyclustering.cluster.center_initializer import kmeans_plusplus_initializer
xm_c = kmeans_plusplus_initializer(X_norm, 2).initialize()
xm_i = xmeans(data=X_norm, initial_centers=xm_c, kmax=20, ccore=True)
xm_i.process()

[実行結果]

クラスタリング結果の可視化

クラスタリング結果を可視化します。

[Google Colaboratory]

1
2
3
4
5
6
7
8
z_xm = np.ones(X_norm.shape[0])
for k in range(len(xm_i._xmeans__clusters)):
z_xm[xm_i._xmeans__clusters[k]] = k+1
plt.figure(figsize=(10,3))
plt.scatter(x,y, c=z_xm)
centers = np.array(xm_i._xmeans__centers)
plt.scatter(centers[:,0],centers[:,1],s=250, marker="*",c="red")
plt.show

[実行結果]

クラスタ数を指定せずに、期待するクラスタ数3となっていることが確認できました。

© 2026 Playing with Python All Rights Reserved.
Theme by hipaper