本篇内容是xxxx深度学习基础课程视频上的,如有侵权,请与我联系,谢谢!
一,理论知识
K-means算法是聚类中的经典算法,数据挖掘十大经典算法之一。
算法接受参数k,然后将事先输入的n个数据对象划分k个聚类;同一聚类中的对象相似度较高;不同聚类中的对象相似度较小。
算法思想:
以空间中k个点为中心点进行聚类,对最靠近他们的对象归类。通过迭代的方法,逐次更新各聚类中心的值,直至得到最好的聚类结果
算法描述:
1)适当选择c个类的出市中心;
2)在第k次迭代中,对任意一个样本,求其到c各中心的距离,将该样本归到距离最短的中心所在的类;
3)利用均值等方法更新该类的中心值;
4)对于所有的c个聚类中心,如果利用2)3)的迭代法更新后,值保持不变,则迭代结束,否则继续迭代。
停止条件:
1)各类点不再发生变化
2)变化小于一定的阈值
3)循环达到一定的次数
举例:
将以上数据分为两类(k=2)
1) 先选择上图红色五角星的两个点作为初始中心点
2)计算每个点到中心点的距离
上图D0第一行0 1 3.61 5 表示4个点到中心点c1(1,1)的距离,第二行 1 0 2.83 4.24表示4个点到中心点c2的距离
3)根据点离中心点最近原则进行分类,第一次迭代分类结果如下:
4)根据分类结果,重新确定中心点坐标,
因为第一类只有1个点c1(1,1),所以中心点坐标还是它,c2有3个点,新的中心点左边为:
更新后分类结果如下图:
5)再计算每个点到中心点的距离,结果如下
根据距离中心点较小的原则归类,结果如下:
6)根据新的分类结果,更新中心点坐标如下:
分类结果如下:
7)再计算各点到中心点的距离,根据最小距离进行归类,发现各类的点已经没有变化了。
8)于是得到最终的分类结果:
二,代码实现
import numpy as np
def kmeans(X,k,maxIt):
#返回X的行列数
numPoints,numDim=X.shape
#在X列的基础上多加入一列,为了放类的标签
dataSet =np.zeros((numPoints,numDim+1))
#不算最后一列,其他行列赋值为X的值
dataSet[:,:-1]=X
#随机产生中心点
centroids=dataSet[np.random.randint(numPoints,size=k),:]
# centroids=dataSet[0:2,:]
centroids[:,-1]=range(1,k+1)
iterations=0
oldCentroids=None
#旧中心点和新中心点不相等,循环次数没达到指定次数
while not shouldStop(oldCentroids,centroids,iterations,maxIt):
print ("iteration: \n",iterations) #第几轮
print("dataSet: \n",dataSet) #数据集
print ("centroids \n",centroids) #中心点
oldCentroids=np.copy(centroids) #将中心点拷出,不能直接用=号
iterations+=1 #轮数加1
updateLabels(dataSet,centroids) #更新标签
centroids=getCentroids(dataSet,k) #获取中心点
return dataSet #返回数据集
#判断要不要停止
def shouldStop(oldCentroids,centroids,iterations,maxIt):
if iterations>maxIt:
return True
return np.array_equal(oldCentroids,centroids)
#更新每个点的类标签
def updateLabels(dataSet,centroids):
numPoints,numDim=dataSet.shape
for i in range(0,numPoints):
#当前行最后一列
dataSet[i,-1]=getLabelFromClosestCentroid(dataSet[i,:-1],centroids)
#比较当前行和每一个中心点距离,选择最近的距离,将其归为该中心点的类
def getLabelFromClosestCentroid(dataSetRow,centroids):
label=centroids[0,-1]; #中心点的类标签
minDist=np.linalg.norm(dataSetRow-centroids[0,:-1]) #先让它等于第一个中心点的距离
for i in range(1,centroids.shape[0]):
dist=np.linalg.norm(dataSetRow-centroids[i,:-1]) #从第二个中心点开始判断
if dist<minDist: #更新最小值
minDist=dist
label=centroids[i,-1] #保存标签
print ("minDist",minDist)
return label
#更新中心点坐标
def getCentroids(dataSet,k):
result=np.zeros((k,dataSet.shape[1]))
for i in range(1,k+1):
oneCluster=dataSet[dataSet[:,-1]==i,:-1]
result[i-1,:-1]=np.mean(oneCluster,axis=0)
result[i-1,-1]=i
return result
x1=np.array([1,1])
x2=np.array([2,1])
x3=np.array([4,3])
x4=np.array([5,4])
testX=np.vstack((x1,x2,x3,x4))
result=kmeans(testX,2,10)
print("final result:")
print(result)
结果: