k-均值聚类的一般过程:
- 收集数据:anyway
- 准备数据:需要数值型数据来计算距离
- 分析数据:anyway
- 训练算法:不适用于无监督学习,即无监督学习没有训练过程
- 测试算法:应用聚类算法、观察结果。可使用量化的误差标准如误差平方和
- 使用算法:簇质心可以代表整个簇的数据来做出决策
K均值聚类算法
#import pprint
from numpy import *
def loadDataSet(filename):
dataMat=[]
fr=open(filename)
for line in fr.readlines():
#默认删除空白符(包括'\n', '\r', '\t', ' ')
curline=line.strip().split('\t')
#python 3.x map return iterator not list as python2.x
fltLine=list(map(float,curline))
dataMat.append(fltLine)
return dataMat
#计算向量的欧式距离
def distEclud(vecA,vecB):
return sqrt(sum(power(vecA-vecB,2)))
#构建包含k个随机质心的集合,其数据点在边界之内(min~max)
def randCent(dataSet,k):
n=shape(dataSet)[1]#返回列数
centroids=mat(zeros((k,n)))
for j in range(n):
#每一维的最大值和最小值
minJ = min(dataSet[:,j])
rangeJ=float(max(dataSet[:,j])-minJ)
centroids[:,j] =minJ + rangeJ * random.rand(k,1)
return centroids
# =============================================================================
# Examples
# --------
# np.random.rand(3,2)
# array([[ 0.14022471, 0.96360618], #random
# [ 0.37601032, 0.25528411], #random
# [ 0.49313049, 0.94909878]]) #random
# =============================================================================
def kMeans(dataSet,k,distMeas=distEclud,createCent=randCent):
m=shape(dataSet)[0]#行数,即数据集中数据点的总数
#簇分配结果矩阵:一列记录簇索引值,二列记录存储误差(当前点到簇质心的距离),可用来评价聚类效果
clusterAssment=mat(zeros((m,2)))
centroids=createCent(dataSet,k)#随机创建初始质心,k*n矩阵
clusterChanged=True
while clusterChanged:#结束条件:簇分配结果不再改变
clusterChanged=False
#遍历所有数据找到距离每个点最近的质心
for i in range(m):
#inf(正无穷) Nan(负无穷)
minDist=inf;minIndex=-1;
for j in range(k):
#计算质心到数据点的欧式距离,此处依次计算每个质心到数据点i的距离
distJI=distMeas(centroids[j,:],dataSet[i,])#dataSet[i,:]=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):
#获得距离同一个质心最近的所有点的下标,即同一簇的坐标
#nonzero 返回的是矩阵中所有非零元素的坐标,坐标的行数与列数个存在一个数组或矩阵当中
# 矩阵支持检查元素的操作,所有可以写成matrix == int这种形式,返回的一个布尔型矩阵,代表矩阵相应位置有无此元素
#clusterAssment[:,0].A---Return self as an ndarray object.Equivalent to np.asarray(self).
ptsInClust=dataSet[nonzero(clusterAssment[:,0].A==cent)[0]]
#axis=0 朝y轴负方向计算均值(即矩阵的列方向)
centroids[cent,:]=mean(ptsInClust,axis=0)
return centroids,clusterAssment#返回质心和点分配结果
使用后处理提高聚类性能---如何判断k是否正确;生成的簇是否比较好
方法:合并最近的质心,或者合并两个使得SSE增幅最小的质心
1.计算所有质心之间的距离,然后合并距离最近的两个点来实现
2.合并两个簇然后计算SSE(误差平方和)总值
二分K-均值算法
伪代码:
将所有点看成一个簇
当簇数目小于k时
对于每一个簇
计算总误差
在给定的簇上面进行k-均值聚类(k=2)
计算将该簇一分为二后的总误差
选择使得误差最小的那个簇进行划分工作
#type(dataSet) is matrix
def biKmeans(dataSet,k,distMeas=distEclud):
m=shape(dataSet)[0]
clusterAssment=mat(zeros((m,2)))
#(.tolist) transport matrix to list and return first cloumn
#[[-0.10 0.05]]-->[[-0.10,0.05]]-->[-0.10,0.05]
centroid0=mean(dataSet,axis=0).tolist()[0]
centList=[centroid0]#[-0.10,0.05]->[[-0.10,0.05]] 簇
#calc the dist between the first centroid0 ans per datapoint
for j in range(m):
clusterAssment[j,1]=distMeas(mat(centroid0),dataSet[j,:])**2
#不停对簇进行划分,直到得到想要的簇数目
while(len(centList)<k):
lowestSSE=inf# sum of squared Error (error between sample and centroid)
for i in range(len(centList)):# 依次遍历centList中的每个簇
#将第i个簇中的所有点看成数据集,并输入带kMeans()中处理,k=2
ptsInClurrCluster=dataSet[nonzero(clusterAssment[:,0].A==i)[0],:]
centroidMat,splitClustAss=kMeans(ptsInClurrCluster,2,distMeas)#质心,簇
sseSplit=sum(splitClustAss[:,1])#划分后数据集簇的误差值
sseNoSplit=sum(clusterAssment[nonzero(clusterAssment[:,0].A!=i)[0],1])#剩余数据集(未参与划分)的误差
print('sseSplit and notSplit',sseSplit,sseNoSplit)
if(sseSplit+sseNoSplit<lowestSSE):
bestCentToSplit=i
bestNewCents=centroidMat
bestClustAss=splitClustAss.copy()
lowestSSE=sseSplit+sseNoSplit
bestClustAss[nonzero(bestClustAss[:,0].A == 1)[0],0] = len(centList)
bestClustAss[nonzero(bestClustAss[:,0].A == 0)[0],0] = bestCentToSplit
print('the bestCentToSplit is: ',bestCentToSplit)
print('the len of bestClustAss is: ',len(bestClustAss))
centList[bestCentToSplit] = bestNewCents[0,:].tolist()[0]#replace a centroid with two best centroids
centList.append(bestNewCents[1,:].tolist()[0])
#reassign new clusters, and SSE
clusterAssment[nonzero(clusterAssment[:,0].A == bestCentToSplit)[0],:]= bestClustAss
return mat(centList), clusterAssment