K-均值算法:首先,随机确定k个初始点作为质心。根据样本与类中心的距离将数据集中的每个点分配到相应的簇中,接着重新计算类中心,迭代直至收敛。
伪代码如下:
创建k个点作为起始质心(随机选择)
当任意一个点的簇分配结果发生改变时:
对数据集中的每个数据点:
对每个质心:
计算质心与数据点之间的距离
将数据点分配到距其最近的簇
对每一个簇,计算簇中所有点的均值并将均值作为质心
一般流程:
- 收集数据;
- 准备数据:需要数值型数据来计算距离,也可以将标记型数据映射为二值型数据再用于距离计算
- 分析数据;
- 训练算法:无监督学习没有训练过程
- 测试算法;
- 使用算法;
K-均值聚类支持函数:
def loadDataSet(filename):
dataMat=[]
fr=open(filename)
for line in fr.readlines():
curLine=line.strip().split('\t')
fltLine=list(map(float,curLine)) #会根据提供的函数(类型)对指定序列做映射,python3中map返回的是迭代器,所以要改成list
dataMat.append(fltLine)
return dataMat
"""计算两个样本之间的距离"""
def distEclud(vecA,vecB):
return sqrt(sum(power(vecA-vecB,2)))
"""为给定的数据集构建一个包含k个随机簇质心的集合"""
"""随机质心必须在整个数据集的边界之内,通过找到数据集每一维的最小和最大值来完成"""
def randCent(dataSet,k):
n=shape(dataSet)[1] #特征数
centroids=mat(zeros((k,n))) #构建k个质心的矩阵,初始化为全0
for j in range(n):
minJ=min(dataSet[:,j]) #找出所有样本中每一个特征的最小特征的样本
rangeJ=float(max(dataSet[:,j])-minJ) #质心的特征可以设置的范围
centroids[:,j]=minJ+rangeJ*random.rand(k,1) #随机k个质心
return centroids
K-均值算法实现:
"""K-Means聚类"""
def kMeans(dataSet,k,distMeas=distEclud,createCent=randCent):
m=shape(dataSet)[0] #样本总数
clusterAssment=mat(zeros((m,2))) #创建一个矩阵,用于存储每个点的簇分配结果,包含两列:记录簇索引值;存储误差(当前点到簇质心的距离)
centroids=createCent(dataSet,k) #初始化簇质心
clusterChanged=True #簇分配发生改变(因为簇质心发生了改变)
while clusterChanged: #迭代
clusterChanged=False
for i in range(m): #遍历每一个样本
minDist=inf
minIndex=-1
for j in range(k): #用该样本和每一个当前质心比较
distJI=distMeas(centroids[j,:],dataSet[i,:]) #找到距离最近的质心
if distJI<minDist:
minDist=distJI #记录最短距离
minIndex=j #记录簇序号(索引)
if clusterAssment[i,0]!=minIndex: #查看当前样本的簇是否和现在分配的簇序号一致
clusterChanged=True
clusterAssment[i,:]=minIndex,minDist**2 #记录误差
print(centroids)
for cent in range(k): #更新质心
ptsInClust=dataSet[nonzero(clusterAssment[:,0].A==cent)[0]]
centroids[cent,:]=mean(ptsInClust,axis=0) #更新方式是计算簇中所有点的均值作为新的质心
return centroids,clusterAssment