はじめに
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()
参考文献
機械学習のエッセンス