1.kmeans算法

   通过随机选取k个质心,计算所有样本点距离k个质心的距离,选取最短的质心,记录下来,(样本点,质心下标,到质心点距离),质心(n个维度值)对应空间维度上一个点,这样就找到k个质心的相似点(简单的计算欧式几何距离),对每个质心的相似点,计算均值(所有n个维度的),然后不断循环,直到整个数据集收敛,没有距离更短的质心出现。


2.二分k均值算法

   

     由于k均值算法刚开始随机选取的质心,而且需要选取k,容易出现k的选取不合适导致整个数据聚类效果不好,产生的是局部最小值,而不是全局最小值。二分k均值算法先把整个数据集作为一个簇,然后二分这个簇。之后选取一个簇继续二分,选取的标准是:是否可以最大程度的降低SSE的值。上述基于SSE值的划分会不断进行,直到得到用户指定的簇的个数。


3.


'''
实现k-means算法
'''
import matplotlib.pyplot as plt
import numpy as np
import random
from numpy import *
from operator import  *

def loadDataSet(fileName):      #general function to parse tab -delimited floats
    dataMat = []                #assume last column is target value
    fr = open(fileName)
    for line in fr.readlines():
        curLine = line.strip().split('\t')
        dataMat.append(list(map(lambda x:float(x),curLine)))
    return dataMat

#计算两个向量之间的欧式距离
def distEclud(vecA,vecB):

    #return sqrt(sum((vecA - vecB).A**2))
    return sqrt(sum(power(vecA-vecB,2)))


#生成k个随机的质心
#质心需要在边界范围内0
def randCent(dataSet,k):
    m,n=shape(dataSet)
    #生成一个(k,n)的矩阵
    #zeros(())注意里面参数是个元组
    centValue=mat(zeros((k,n)))
    print('centValue',centValue)
    #循环生成n个列向量,对应矩阵的n个向量,在n个向量的最小值和最大值范围内,向量的元素个数为k
    for i in range(n):
        minV=min(dataSet[:,i])
        ranV=max(dataSet[:,i])-minV
        centValue[:,i]=minV.tolist()[0][0]+(ranV.tolist()[0][0])*(random.rand(k,1))

    return centValue


#画图
#画散点图
def plot(dataSet,centValue,centList):

    x1=dataSet[:,0]
    x2=dataSet[:,1]
    fig=plt.figure('k均值算法')
    ax=fig.add_subplot(111)

    ax.scatter(list(x1),list(x2),s=15,c='red',marker='s')
    ax.scatter(list(centValue[:,0]), list(centValue[:,1]), s=15, c='green', marker='x')
    ax.scatter(list(centList[:, 0]), list(centList[:, 1]), s=15, c='blue', marker='x')

    plt.show()




#k均值算法
def kMeans(dataSet,k,caclDistance=distEclud,gerRandCent=randCent):
    m,n=shape(dataSet)
    #随机生成k个质心
    centValue=gerRandCent(dataSet, k)
    #创建存储样本点距离质心的最短距离和质心下标的临时列表,初始化的为一些无效值
    clusterList=mat(zeros((m,2)))
    clusterList[:,0]=-1
    clusterList[:,1]=inf

    #循环计算每个样本点距离质心的最短距离,直到获取到所有样本点最新的质心

    isChanged=True
    while isChanged:
        isChanged=False
        for i in range(m):

            # 选择距离当前样本点最新的那个质心
            minIndx = clusterList[i, 0]
            minDist = clusterList[i, 1]
            for j in range(k):

                tempDist = (caclDistance(dataSet[i, :], centValue[j, :])) ** 2

                if tempDist < minDist:
                    minDist = tempDist
                    minIndx = j

            # 发现更小的
            if clusterList[i, 0] != minIndx:
                isChanged=True
                clusterList[i, :] = minIndx, minDist

        # 更新质心
        for i in range(k):
            # 获取第k个质心临近的样本点
            kData = dataSet[nonzero(clusterList[:, 0] == i)[0]]
            # 取列方向的平均值
            centValue[i, :] = mean(kData, axis=0)
        print('centValue:\n',centValue)

    return centValue,clusterList


#二分法寻找最优聚类

def biKmeans(dataSet, k, distMeas=distEclud):
    m = shape(dataSet)[0]
    clusterAssment = mat(zeros((m,2)))
    centroid0 = mean(dataSet, axis=0).tolist()[0]
    centList =[centroid0] #create a list with one centroid
    for j in range(m):#calc initial Error
        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
            #使用kMean算法对当前数据集进行二分,产生两个质心和对应样本点距离两个质心的最短距离,注意是针对上面等于当前质心下标的样本点
            centroidMat, splitClustAss = kMeans(ptsInCurrCluster, 2, distMeas)
            #计算划分的SSE,即误差和(一个质心变两个,对应着一个样本集变两个)
            sseSplit = sum(splitClustAss[:,1])#compare the SSE to the currrent minimum
            #计算非当前质心的其他质心的SSE
            sseNotSplit = sum(clusterAssment[nonzero(clusterAssment[:,0].A!=i)[0],1])
            print("sseSplit, and notSplit: ",sseSplit,sseNotSplit)
            #计算划分后的最优SSE,即最有序的生成簇
            if (sseSplit + sseNotSplit) < lowestSSE:
                #最优的需要拆分的质心:一个簇,变成两个
                bestCentToSplit = i
                #最优的二分质心点的值
                bestNewCents = centroidMat
                #最优的距离上面两个质心的样本的距离
                bestClustAss = splitClustAss.copy()
                #最优的SSE的值
                lowestSSE = sseSplit + sseNotSplit
        #更新最优的距离上面两个质心的样本的距离矩阵等于1的(产生两个质心中的一个)质心值,取当前质心列表元素的个数(原来下标是0-len(cenList)-1)
        #对应下面的向质心列表中新增那个质心下标
        bestClustAss[nonzero(bestClustAss[:,0].A == 1)[0],0] = len(centList) #change 1 to 3,4, or whatever
        #更新最优的距离上面两个质心的样本的距离矩阵等于0的(产生两个质心中的一个)质心值,取最优的质心,也就是要进行划分的那个质心
        bestClustAss[nonzero(bestClustAss[:,0].A == 0)[0],0] = bestCentToSplit
        print('the bestCentToSplit is: ',bestCentToSplit)
        print('the len of bestClustAss is: ', len(bestClustAss))
        #更新质心列表
        #被划分的那个质心,对应的点的值,取0的对应的二分后的那个质质心值
        centList[bestCentToSplit] = bestNewCents[0,:].tolist()[0]#replace a centroid with two best centroids
        #新增一个质心
        centList.append(bestNewCents[1,:].tolist()[0])
        print("划分前的最优距离:\n", shape(clusterAssment[nonzero(clusterAssment[:, 0].A == bestCentToSplit)[0], :]))
        print('划分后的最优距离:\n',shape(bestClustAss))
        #更新原来到最优质心的那些样本点对应的值,改成现在新的质心和对应距离,完成划分的动作,两者的shape应该一样的,因为对bestCentToSplit
        #划分前后,分成质心0和质心1两个集合
        clusterAssment[nonzero(clusterAssment[:,0].A == bestCentToSplit)[0],:]= bestClustAss#reassign new clusters, and SSE

    return mat(centList), clusterAssment





fileName=r'D:\software\python\sourcecode_and_data\MLiA_SourceCode\machinelearninginaction\Ch10\testSet2.txt'

dataSet=loadDataSet(fileName)

print('数据集:\n',mat(dataSet))


dataSetMatrix=mat(dataSet)

distance=distEclud(dataSetMatrix[0],dataSetMatrix[1])

print('向量距离:\n',distance)

centValue2=randCent(dataSetMatrix,2)

print('质心:\n',centValue2)

centValue,clusterList=kMeans(dataSetMatrix,4)


centList, clusterAssment=biKmeans(dataSetMatrix, 4)

print('centList:\n',centList)

print('clusterAssment:\n',clusterAssment)

plot(dataSetMatrix,centValue,centList)
  

   

kmeans算法--《机器学习实战》总结


相关文章:

  • 2021-06-02
  • 2021-12-29
  • 2021-05-27
  • 2021-04-03
  • 2021-07-04
  • 2021-07-25
猜你喜欢
  • 2021-06-20
  • 2021-05-30
  • 2021-10-04
  • 2021-12-23
  • 2021-05-24
  • 2021-11-15
  • 2022-12-23
相关资源
相似解决方案