1
1

More than 1 year has passed since last update.

【Python】教師なしクラスタリング k-means法

Last updated at Posted at 2023-04-08

k-means法は古典的な非階層的クラスタリング手法で、サンプルデータをK個のクラスターに分け、中心点からの距離の近さにより分類するという方法です。

クラスタリングの流れ

  1. クラスタ数をk個指定して、セントロイド(中心点)をランダムにk個配置する
  2. 各サンプルを近接するセントロイドに割り当てる
  3. セントロイドに割り当てたサンプルの中心を求め、セントロイドを移動させる
  4. 2.と3.を繰り返し、中心点が変わらなくなったら、クラスタリング終了

1. Numpyで実装

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets

iris = datasets.load_iris()       # irisを読み込む関数
df = pd.DataFrame(        
    iris.data,                    # データフレームの要素
    columns = iris.feature_names  # 各列の名前に特徴名を使う
)

# iris.target には種類が格納されている
df["label"] = iris.target         # わかりやすくするためにlabel列を追加、ここにクラス番号を入れておきます。

print(df)

input_data = df.iloc[:,:-1].values # インスタンス属性valuesにアクセスすると、np.arrayが取得できます。

def kmeans(k, X, max_iter=300):
    X_size,n_features = X.shape # 150 4
    
    # ランダムに重心の初期値を初期化
    centroids  = X[np.random.choice(X_size,k)] # X[ 17 105  56]

    # 前の重心と比較するために、仮に新しい重心を入れておく配列を用意
    new_centroids = np.zeros((k, n_features))
    
    # 各データ所属クラスタ情報を保存する配列を用意
    cluster = np.zeros(X_size)
    
    # ループ上限回数まで繰り返し
    for epoch in range(max_iter):
        
        # 入力データ全てに対して繰り返し
        for i in range(X_size):
            
            # データから各重心までの距離を計算(ルートを取らなくても大小関係は変わらないので省略)
            distances = np.sum((centroids - X[i]) ** 2, axis=1)
            
            # データの所属クラスタを距離の一番近い重心を持つものに更新
            cluster[i] = np.argsort(distances)[0]
            
        # すべてのクラスタに対して重心を再計算
        for j in range(k):
            new_centroids[j] = X[cluster==j].mean(axis=0)
            
        # もしも重心が変わっていなかったら終了
        if np.sum(new_centroids == centroids) == k:
            print("break")
            break
        centroids =  new_centroids
    return cluster

cluster=kmeans(3, input_data)

df["cluster"] = cluster
df.plot(kind="scatter", x=0,y=1,c="label", cmap="winter") # cmapで散布図の色を変えられます。
plt.title("true label")
plt.show()

df["cluster"] = cluster
df.plot(kind="scatter", x=2,y=3,c="label", cmap="winter") # cmapで散布図の色を変えられます。
plt.title("true label")
plt.show()

df.plot(kind="scatter", x=0,y=1,c="cluster", cmap="winter") # cmapで散布図の色を変えられます。
plt.title("clustering relust")
plt.show()

df.plot(kind="scatter", x=2,y=3,c="cluster", cmap="winter") # cmapで散布図の色を変えられます。
plt.title("clustering relust")
plt.show()

2. skleanで実装

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
import seaborn as sns
from sklearn.cluster import KMeans

iris = datasets.load_iris()
df = pd.DataFrame(        
    iris.data,
    columns = iris.feature_names
)

df['target'] = iris.target
sns.pairplot(df, hue="target")
plt.show()

df["label"] = iris.target
print(df)

input_data = df.iloc[:,:-1].values

n_clusters = 2
clf = KMeans(n_clusters=n_clusters, init='k-means++', n_init=10, max_iter=300,tol=0.0001)
pred = clf.fit_predict(input_data)

df['label'] = pred
df.plot(kind="scatter", x=0,y=1,c="label", cmap="winter")
plt.title("clustering relust")
plt.show()

まとめ

今回は、非階層的なクラスタリング手法であるk-mean法を、Numpyとskleanを用いて実装する方法を紹介した。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1