K-均值(K-means)聚类算法

时间:2022-03-18 23:17:38

聚类是一种无监督的学习,它将相似的对象归到同一个簇中。

这篇文章介绍一种称为K-均值的聚类算法,之所以称为K-均值是因为它可以发现k个不同的簇,且每个簇的中心采用簇中所含值的均值计算而成。

聚类分析视图将相似对象归入同一簇,将不相似对象归到不同簇。

下面用Python简单演示该算法实现的原理:

函数loadDataSet先将文本文件导入到一个列表中,并添加到dataSet中,返回的结果即为需加载的训练数据。

def loadDataSet(fileName):
    dataMat = []
    fr = open(fileName)
    for line in fr.readlines():
        curLine = line.strip().split('\t')
        fltLine = map(float,curLine)
        dataMat.append(list(fltLine))
    return dataMat

 函数distEclud用于计算两个向量的距离:

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

def randCent(dataSet,k):
    n = shape(dataSet)[1]   # 列数
    centroids = mat(zeros((k,n)))  # 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

 函数randCent有两个参数,其中k为用户指定的质心的数量(即最后分成的类的个数),该函数的作用是为给定的数据集dataSet构建一个包含k个随机质心的集合(centroids)。

上面三个为辅助函数,下面为完整的K-均值算法:

def kMeans(dataSet,k,disMeas = distEclud, createCent = randCent):
    m = shape(dataSet)[0]  # 训练数据集的数量
    clusterAssent = 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 = disMeas(centroids[j,:], dataSet[i ,:])
                if distJI < minDist:
                    minDist = distJI
                    minIndex = j
            if clusterAssent[i,0] != minIndex:
                clusterChanged = True    # 任何一个点对应的质心发生变化需要重新遍历计算
            clusterAssent[i,:] = minIndex,minDist ** 2
        print(centroids)
        for cent in range(k):   # 更新质心的位置
            ptsInClust = dataSet[nonzero(clusterAssent[:,0].A == cent)[0]]
            centroids[cent : ] = mean(ptsInClust, axis= 0)
    return centroids,clusterAssent

 思路大概为:

  • 遍历所有训练数据点(m个数据点)
    • 对所有质心(k个质心)
      • 计算该数据点与质心之间的距离,并保存该数据点最近的质心
    • 对比之前保存的该数据点的质心(即该数据点所属的簇,保存在clusterAssent中),若发生更改,则证明未收敛,结束后需要从头开始循环
  • 对于每一个簇,计算簇中所有点的均值作为质心。

K-均值算法有时候会出现聚类效果较差,收敛到了局部最小值,而非全局最小值。一种用于度量聚类效果的指标是SSE(Sum of Squared Error,误差平方和),SSE越小表示数据点越接近于它们的质心,聚类效果也越好。因此,要对聚类的结果进行改进的方法可以将具有最大SSE值的簇划分为两个簇,同时为了保持簇总数不变,可以将某两个簇进行合并。