機械学習基礎理論独習

誤りがあればご指摘いただけると幸いです。数式が整うまで少し時間かかります。リンクフリーです。

勉強ログです。リンクフリーです
目次へ戻る

【Python自前実装】K-means法

はじめに

Kmeans法はアルゴリズムが単純なので、ソースだけ貼り付けます。
コメントをたくさん書いているので、参考にしてください。

ソース

import numpy as np
import matplotlib.pyplot as plt

class KMeans:
    def __init__(self, n_clusters, max_iter=1000, random_seed=0):
        self.n_clusters = n_clusters
        self.max_iter = max_iter
        self.random_state = np.random.RandomState(random_seed)

    # 学習
    def fit(self, X):
        # ラベルを順番に指定 ex.[0,1,2,0,1,2,...]
        self.labels_ = np.array([x % self.n_clusters for x in range(X.shape[0])])
        
        # ラベルをシャッフルする
        self.random_state.shuffle(self.labels_)
        
        # 1つ前のラベルを 0 に初期化する
        labels_prev = np.zeros(X.shape[0])
        
        # カウントを 0 に初期化する。このカウントはループをカウントする変数。
        count = 0
        
        # クラスタの位置をランダムに決める
        rand = np.random.randn(self.n_clusters, X.shape[1])
        max = np.max(X,axis=0)
        min = np.min(X,axis=0)
        self.cluster_centers_ = min + rand * (max - min)
        
        while (not (self.labels_ == labels_prev).all() and count < self.max_iter):
            for i in range(self.n_clusters):
                # クラスタ i の平均をクラスタに属するデータの重心で更新する
                XX = X[self.labels_ == i, :]
                self.cluster_centers_[i, :] = XX.mean(axis=0)
                
            # クラスタの距離を計算する
            # X[:, :, np.newaxis].shape == (150, 2, 1)
            # self.cluster_centers_.T[np.newaxis, :, :].shape === (1, 2, 3)
            dist = ((X[:, :, np.newaxis] - self.cluster_centers_.T[np.newaxis, :, :]) ** 2).sum(axis=1)
            
            # 現在のデータをコピー
            labels_prev = self.labels_
            
            # ラベルを距離が最も近いクラスタに更新する
            self.labels_ = dist.argmin(axis=1)
            
            # カウントを増やす
            count += 1

    # 予測する
    def predict(self, X):
        dist = ((X[:, :, np.newaxis] - self.cluster_centers_.T[np.newaxis, :, :]) ** 2).sum(axis=1)
        labels = dist.argmin(axis=1)
        return labels

np.random.seed(0)

# データ作成
p1 = np.random.randn(50, 2)
p2 = np.random.randn(50, 2) + np.array([5, 0])
p3 = np.random.randn(50, 2) + np.array([5, 5])
data = np.r_[p1, p2, p3]

# モデル作成
model = KMeans(3)

# 学習
model.fit(data)

# 描画
for i in range(3):
    p = data[model.labels_ == i, :]
    plt.scatter(p[:, 0], p[:, 1])

plt.show()

f:id:olj611:20211118202122p:plain:w400

参考文献

機械学習のエッセンス

目次へ戻る