pythonで、kmeansを実装したいのですが、予想外の結果が出てきて驚いています。
コードを以下に示します。
Python
1import numpy as np 2from sklearn.datasets import load_iris 3import matplotlib.pyplot as plt 4%matplotlib inline 5 6iris=load_iris() 7data=iris.data 8label=iris.target 9plt.scatter(data[:,0],data[:,1],c=label) 10 11def culc_dist(target_data,centroid):#距離の計算 12 dist_holder=(target_data-centroid)**2 13 distance=np.sqrt(np.sum(dist_holder,axis=1)) 14 n_cluster=np.argmin(distance) 15 dist=distance[n_cluster] 16 return n_cluster,dist 17 18class kmeans: 19 def __init__(self,K,max_iter=100):#クラスターの数と、最大学習回数の初期化関数 20 if K < 2 or not(isinstance(K,int)):#Kは、学習回数2以上でかつ整数 21 raise ValueError("クラスター数に不適切な値が入力されています") 22 else: 23 self.K=K 24 25 if not(isinstance(max_iter,int)):#学習回数は、整数 26 raise ValueError("学習回数に不適切な値が入力されています。") 27 else: 28 self.max_iter=max_iter 29 30 def fit(self, X, y=None):#学習データのセット関数 31 self.X=X 32 self.y=np.zeros(self.X.shape[0]) 33 self.n_feature=X.shape[1] 34 self.centroids=np.random.uniform(0 , 1 , (self.K , self.n_feature)) 35 self.new_centroids=np.random.uniform(0 , 1 , (self.K , self.n_feature)) 36 self.SSE=0 37 38 def cluster_learn(self):#学習開始関数 39 for iter in range(self.max_iter):#学習回数分ループ 40 for data_index in range(self.X.shape[0]):#データの個数分ループ 41 n_cluster,dist=culc_dist(self.X[data_index],self.centroids) 42 self.y[data_index]=n_cluster 43 self.SSE+=dist 44 for label_num in range(self.K):#クラスター数分ループ 45 k_mask=(self.y==label_num) 46 masking_data=self.X[k_mask] 47 for feature in range(masking_data.shape[1]):#データの数分ループ 48 self.new_centroids[label_num][feature]=np.average(masking_data[:,feature]) 49 if (self.centroids==self.new_centroids).any(): 50 return self.centroids,self.y,self.SSE 51 else: 52 self.centroids=self.new_centroids 53 return self.centroids,self.y,self.SSE 54 55a=kmeans(3) 56a.fit(iris.data) 57a.cluster_learn() 58
実行結果がこちらです。
(array([[5.84333333, 3.05733333, 3.758 , 1.19933333], [ nan, nan, nan, nan], [ nan, nan, nan, nan]]), array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]), nan)
なぜか、クラスターがちゃんと保存されません。
おそらくcentroidから各データまでの距離の計算がおかしいんだと思いますが、どこが間違っているのかわかりません。
また、何回か実行するときちんとクラスタリングされるタイミングがあるのですが、それもなぜかわかりません。
こちらがそのうまくった例です。
(array([[4.65714286, 2.62857143, 2.1 , 0.55714286], [6.30103093, 2.88659794, 4.95876289, 1.69587629], [5.05869565, 3.4826087 , 1.47826087, 0.25 ]]), array([2., 2., 2., 2., 2., 2., 2., 2., 0., 2., 2., 2., 2., 0., 2., 2., 2., 2., 2., 2., 2., 2., 2., 2., 2., 2., 2., 2., 2., 2., 2., 2., 2., 2., 2., 2., 2., 2., 0., 2., 2., 0., 2., 2., 2., 2., 2., 2., 2., 2., 1., 1., 1., 1., 1., 1., 1., 0., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 0., 1., 1., 1., 1., 0., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.]), 1167.5006234945204)
どうすればいいでしょうか。
よろしくお願いいたします。
回答1件
あなたの回答
tips
プレビュー