1.算法流程
1.1 确定参数:指定要划分的簇数k。
1.2 初始化质心:从所有数据样本中随机选取k个样本,作为k个簇的初始 "质心"。
1.3 样本分配:计算每个样本到k个质心的距离,将样本分配给距离最近的质心所属的簇。
1.4 更新质心:对每个簇,计算其所有样本的特征均值,用这个均值替换原质心。
1.5 迭代收敛:重复 "样本分配→更新质心" 的步骤,直到质心的位置不再明显变化,算法停止。
2.代码实现
python
# -*- coding: utf-8 -*-
import numpy as np
import matplotlib.pyplot as plt
def L2(vecXi, vecXj):
'''
计算欧氏距离
para vecXi:点坐标,向量
para vecXj:点坐标,向量
retrurn: 两点之间的欧氏距离
'''
return np.sqrt(np.sum(np.power(vecXi - vecXj, 2)))
def kMeans(S, k, distMeas=L2):
'''
K均值聚类
para S:样本集,多维数组
para k:簇个数
para distMeas:距离度量函数,默认为欧氏距离计算函数
return sampleTag:一维数组,存储样本对应的簇标记
return clusterCents:一维数组,各簇中心
retrun SSE:误差平方和
'''
m = np.shape(S)[0] # 样本总数
sampleTag = np.zeros(m)
# 随机产生k个初始簇中心
n = np.shape(S)[1] # 样本向量的特征数
clusterCents = np.mat([[-1.93964824,2.33260803],[7.79822795,6.72621783],[10.64183154,0.20088133]])
#clusterCents = np.mat(np.zeros((k,n)))
#for j in range(n):
# minJ = min(S[:,j])
# rangeJ = float(max(S[:,j]) - minJ)
# clusterCents[:,j] = np.mat(minJ + rangeJ * np.random.rand(k,1))
sampleTagChanged = True
SSE = 0.0
while sampleTagChanged: # 如果没有点发生分配结果改变,则结束
sampleTagChanged = False
SSE = 0.0
# 计算每个样本点到各簇中心的距离
for i in range(m):
minD = np.inf
minIndex = -1
for j in range(k):
d = distMeas(clusterCents[j,:],S[i,:])
if d < minD:
minD = d
minIndex = j
if sampleTag[i] != minIndex:
sampleTagChanged = True
sampleTag[i] = minIndex
SSE += minD**2
print(clusterCents)
plt.scatter(clusterCents[:,0].tolist(),clusterCents[:,1].tolist(),c='r',marker='^',linewidths=7)
plt.scatter(S[:,0],S[:,1],c=sampleTag,linewidths=np.power(sampleTag+0.5, 2))
plt.show()
print(SSE)
# 重新计算簇中心
for i in range(k):
ClustI = S[np.nonzero(sampleTag[:]==i)[0]]
clusterCents[i,:] = np.mean(ClustI, axis=0)
return clusterCents, sampleTag, SSE
if __name__=='__main__':
samples = np.loadtxt("kmeansSamples.txt")
clusterCents, sampleTag, SSE = kMeans(samples, 3)
#plt.scatter(clusterCents[:,0].tolist(),clusterCents[:,1].tolist(),c='r',marker='^')
#plt.scatter(samples[:,0],samples[:,1],c=sampleTag,linewidths=np.power(sampleTag+0.5, 2))
plt.show()
print(clusterCents)
print(SSE)