聚类之K-均值聚类

此文为《机器学习实战》《机器学习》学习笔记

一、聚类

在无监督学习中,学习的样本在训练之前无类别标记。聚类方法作为重要的无监督学习方法,学习的过程就是要将这些样本根据某特性的相似性来进行划分,相似性大到某一程度的数据样本将被放在一类中,得到一个个通常不相交的子集,这些子集也被称为簇,也就是说聚类的结果就是得到一些簇,但是簇内的数据的相似性是内在的,我们并不知道,簇识别就是去得知这些簇到底是什么。

二、K-均值聚类

此种聚类方法适用于数值型数据。该方法中可以发现 k 个不同的簇,并且每个簇中的中心取簇中所含值的均值,因此被称为K-均值聚类,k值由用户指定。在上段所说我们需要将在某方面相似的数据归到同一簇,相似的概念取决于所采用的相似度计算方法,比如欧氏距离。

以下例子实现了简单的K-均值聚类算法

def distEclud(vecA, vecB):
    return sqrt(sum(power(vecA - vecB, 2))) #计算欧式距离

def randCent(dataSet, k):
    n = shape(dataSet)[1]
    centroids = mat(zeros((k,n)))#创建质心向量
    for j in range(n):#此向量包含k组质心,每组中包含一个样本中的各个数据的质心
        minJ = min(dataSet[:,j]) 
        rangeJ = float(max(dataSet[:,j]) - minJ)
        centroids[:,j] = mat(minJ + rangeJ * random.rand(k,1))
    return centroids
    
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

三、二分K-均值算法

以上k-均值算法存在问题,其一是用户自定义的 k 值不知道是否合适;其二该算法收敛到了局部最小值,不能收敛到全局最小值。

二分K-均值算法首先将所有数据作为一个簇,然后一分为二,再选择其中之一继续一分为二。

SSE是误差平方和,在算法中,我们使用 clusterAssment 来记录数据的簇信息,包含两部分,第二部分为该数据与质心的距离平方值。

def biKmeans(dataSet, k, distMeas=distEclud):
    m = shape(dataSet)[0]
    clusterAssment = mat(zeros((m,2)))
    centroid0 = mean(dataSet, axis=0).tolist()[0]
    centList =[centroid0] #创建一个初始簇
    for j in range(m):#
        clusterAssment[j,1] = distMeas(mat(centroid0), dataSet[j,:])**2
    while (len(centList) < k):
        lowestSSE = inf
        for i in range(len(centList)):
            ptsInCurrCluster = dataSet[nonzero(clusterAssment[:,0].A==i)[0],:]#get the data points currently in cluster i
            centroidMat, splitClustAss = kMeans(ptsInCurrCluster, 2, distMeas)
            sseSplit = sum(splitClustAss[:,1])#比较当下最小SSE
            sseNotSplit = sum(clusterAssment[nonzero(clusterAssment[:,0].A!=i)[0],1])
            print "sseSplit, and notSplit: ",sseSplit,sseNotSplit
            if (sseSplit + sseNotSplit) < lowestSSE:
                bestCentToSplit = i
                bestNewCents = centroidMat
                bestClustAss = splitClustAss.copy()
                lowestSSE = sseSplit + sseNotSplit
        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]#替换质心
        centList.append(bestNewCents[1,:].tolist()[0])
        clusterAssment[nonzero(clusterAssment[:,0].A == bestCentToSplit)[0],:]= bestClustAss
    return mat(centList), clusterAssment

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值