算法思想:
以空间中K个点为中心,对最靠近他们的点进行归类,通过迭代,逐次更新各聚类中心点的值,直到有最好的聚类效果
算法描述:
1)开始随机选中k个点作为初始中心
2)开始迭代,求其到各中心ci的距离,算出距离di,选出di最小的一个中心点,作为这个点所在类
3)利用均值的方法更新该类的中心值,也就是把迭代过后,所有属于某个中心点的值的x和y进行求平均找到新的中心点
4)对于所有的c个聚类中心,如果利用(2)(3)的方法迭代更新后,值保持不变,则迭代结束(或者达到一定的次数),否则继续迭代
算法流程:
输入k,data[n]
1)选择k个初始中心点c[0] = data[0],.....,c[k-1]=data[k-1]
2)对于data[0], ...... data[n-1] 分别与c[0] ....c[k-1]比较,选出差值最小的,标记为i
3)对于所有标记点相同的,重新计算c[i]的值
4)重复(2)(3)操作,直到所有c[i]值的变化小于给定阈值
代码实现
import numpy as np
def Kmeans(X, k, maxIt):
# numPoints 是 X 的行数量,numDim是X的列数量
numPoints = X.shape[0]
numDim = X.shape[1]
# 因为X只有 x,y两个特征,需要最后聚类后的分类结果,所以需要让矩阵多一个列
dataSet = np.zeros((numPoints, numDim + 1))
# 把X的内容赋值给dataSet的第一列和第二列,所以第三列的分类结果初始值为0
# 逗号前是行,逗号后是列
dataSet[:, :-1] = X
#centroids = dataSet[np.random.randint(numPoints, size=k), :]
centroids = dataSet[0:2,:]
# 把中心点初始化为 1->k+1
centroids[:, -1] = range(1, k + 1)
iterations = 0
oldCentroids = None
while not shouldStop(oldCentroids, centroids, iterations, maxIt):
print("iterations: \n" + str(iterations))
print("dataSet: \n" ,dataSet)
print("centroids: \n" , centroids)
#把centroids的值赋值给oldCentroids
oldCentroids = np.copy(centroids)
iterations += 1
#更新结果集
updateLabels(dataSet, centroids)
#根据新的结果集创建新的中心结点
centroids = getCentroids(dataSet, k)
return dataSet
def updateLabels(dataSet, centroids):
numPoints, numDim = dataSet.shape
# 根据点的数量进行遍历
for i in range(0, numPoints):
#dataSet[i,-1]代表的是dataSet第i行的数据,dataSet[i,:-1]代表的是i行最后一列
#获取距离最近的点
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 shouldStop(oldCentroids, centroids, iterations, maxIt):
if iterations > maxIt:
return True
return np.array_equal(oldCentroids, centroids)
#构建新的中心点,通过
def getCentroids(dataSet, k):
#k代表的是行的大小,dataSet.shape[1]代表的是列的大小
result = np.zeros((k, dataSet.shape[1]))
for i in range(1, k + 1):
print("dataSet[:,-1]:",dataSet[:,-1] == i)
#dataSet[dataSet[:, -1] == i, :-1]截取的是与i值相同的也就是dataSet[:,-1] == i 结果为true的值,
# 也就是dataSet最后一列的值和 i值相同
#得到一个聚类点
oneCluster = dataSet[dataSet[:, -1] == i, :-1]
print("oneCluster:",oneCluster)
#压缩行,对各列求均值,返回 1* n 矩阵
#把一个聚类点的一行进行求平均,将其结果放入result的第i-1行的前两列
result[i - 1, :-1] = np.mean(oneCluster, axis=0)
#给最后一列赋值 i 的值 得到新的中心数据点
result[i - 1, -1] = i
return result
if __name__ == '__main__':
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:",result)