for i,item inenumerate(self.data):#对于每一个样本点 c=[]#分别计算该样本点到k个聚类中心的距离,并存入c for j inrange(len(self.centers)): c.append(self.cal_dist(item,self.centers[j])) #print(c) self.targets[i]=np.argmin(c)#更新targets
#更新聚类中心 new_centers=[] for i inrange(self.k):#对于每一个类中的全部样本点 #此时target的取值集合是0到k-1 #挑选出属于簇i的全部样本 i_data=[] for index,item inenumerate(self.data): if self.targets[index]==i: i_data.append(item) iflen(i_data)!=0: cent=[]#存储新的聚类中心的每一个维度 for p inrange(len(self.data[0])):#对于点的每一个维度 sums=0
#计算第i个簇中,每个维度的新值 for x in i_data: sums+=x[p] res=sums/len(i_data) cent.append(res) new_centers.append(cent) else: new_centers.append(self.centers[i])#若某一个簇中所含样本数为0,则不更新该簇的中心点 self.centers=new_centers
defone_step(self): for i,item inenumerate(self.data):#对于每一个样本点 c=[]#分别计算该样本点到k个聚类中心的距离,并存入c for j inrange(len(self.centers)): c.append(self.cal_dist(item,self.centers[j])) #print(c) self.targets[i]=np.argmin(c)#更新targets
#更新聚类中心 new_centers=[] for i inrange(self.k):#对于每一个类中的全部样本点 #此时target的取值集合是0到k-1 #挑选出属于簇i的全部样本 i_data=[] for index,item inenumerate(self.data): if self.targets[index]==i: i_data.append(item) iflen(i_data)!=0: cent=[]#存储新的聚类中心的每一个维度 for p inrange(len(self.data[0])):#对于点的每一个维度 sums=0
#计算第i个簇中,每个维度的新值 for x in i_data: sums+=x[p] res=sums/len(i_data) cent.append(res) new_centers.append(cent) else: new_centers.append(self.centers[i])#若某一个簇中所含样本数为0,则不更新该簇的中心点 self.centers=new_centers
有了上面实现的这些方法,第(4)步的实现就很简单啦,直接来个for循环即可
1 2 3 4 5 6 7
defrun(self,iterations): self.initialize()#初始化聚类中心和各样本所属类别 #经过iterations次迭代,基本就完成了聚类 for it inrange(iterations): #print('iterations',it) self.one_step() return self.centers,self.targets
到这里,我们就完成了整个k-means算法,是时候测试一下效果了。
我们的训练数据是随机生成的,共100个样本,每个样本含2个特征。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
import matplotlib.pyplot as plt import numpy as np if __name__ == '__main__': datasets=np.random.randint(0,100,size=(100,2)) k=4#聚类数 iterations=100#总迭代次数 mykmeans=MyKmeans(k,datasets,True)#实例化 centers,targets=mykmeans.run(iterations)#迭代求解 #可视化聚类结果 plt.scatter(datasets[:,0],datasets[:,1],c=targets) for center in centers: plt.scatter(center[0],center[1],marker='*',s=300) plt.text(center[0], center[1], (round(center[0],2),round(center[1],2)), fontsize=10, color = "r") plt.show()
classMyKmeans: def__init__(self,k,data,do_shuffle=False): self.k=k self.data=data self.do_shuffle=do_shuffle #计算欧氏距离 defcal_dist(self,p1,p2): return np.sqrt(np.sum((p1-p2)**2)) #初始化聚类中心和每个样本所属类别 definitialize(self): if self.do_shuffle: np.random.shuffle(self.data) #初始化聚类中心 self.centers=self.data[:self.k] #初始化每个样本所属簇 self.targets=np.zeros(self.data.shape[0]) defone_step(self): for i,item inenumerate(self.data):#对于每一个样本点 c=[]#分别计算该样本点到k个聚类中心的距离,并存入c for j inrange(len(self.centers)): c.append(self.cal_dist(item,self.centers[j])) #print(c) self.targets[i]=np.argmin(c)#更新targets
#更新聚类中心 new_centers=[] for i inrange(self.k):#对于每一个类中的全部样本点 #此时target的取值集合是0到k-1 #挑选出属于簇i的全部样本 i_data=[] for index,item inenumerate(self.data): if self.targets[index]==i: i_data.append(item) iflen(i_data)!=0: cent=[]#存储新的聚类中心的每一个维度 for p inrange(len(self.data[0])):#对于点的每一个维度 sums=0
#计算第i个簇中,每个维度的新值 for x in i_data: sums+=x[p] res=sums/len(i_data) cent.append(res) new_centers.append(cent) else: new_centers.append(self.centers[i])#若某一个簇中所含样本数为0,则不更新该簇的中心点 self.centers=new_centers defrun(self,iterations): self.initialize()#初始化聚类中心和各样本所属类别 #经过iterations次迭代,基本就完成了聚类 for it inrange(iterations): #print('iterations',it) self.one_step() return self.centers,self.targets