K-Means聚类算法的实现

前言

          本文为我的期末大作业,知识原理参考了他人的文章,并不全是我的想法,有不足之处请指出 。

    K-均值聚类算法的原理与实现

一 K-均值聚类算法的原理

1.1聚类介绍

聚类是一种无监督的学习,它将相似的对象归到同一个簇中,聚类方法几乎可以应用于所有对象,簇内的对象越相似,聚类的效果越好,在现实中我们用到很多的簇的类型,使用不同的簇类型划分数据的结果是不同的,如下的几种簇类型:

(1)明显分离的:不同组中任意两点之间的距离都大于组内任意两点之间的距离,明显分离的簇不一定是球形的,可以具有任意的形状。

(2)基于原型的:簇是对象的集合,其中每个对象到定义该簇的原型的距离比其他簇的原型距离更近,在一个簇中的数据到其中心点比到另一个簇的中心点更近。这是一种常见的基于中心的簇,最常用的K-Means就是这样的一种簇类型,这样的簇趋向于球形。

(3)基于密度的:簇是对象的密度区域,当簇不规则或相互盘绕,并且有早上和离群点事,常常使用基于密度的簇定义。

基本的聚类分析算法有如下几种:

(1) K均值:基于原型的、划分的距离技术,它试图发现用户指定个数(K)的簇。

(2)凝聚的层次距离:思想是开始时,每个点都作为一个单点簇,然后,重复的合并两个最靠近的簇,直到尝试单个、包含所有点的簇。

(3)DBSCAN: 一种基于密度的划分距离的算法,簇的个数有算法自动的确定,低密度中的点被视为噪声而忽略,因此其不产生完全聚类。

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

K-Means算法的思想,对于给定的样本集,按照样本之间的距离大小,将样本集划分为K个簇。让簇内的点尽量紧密的连在一起,而让簇间的距离尽量的大。

1.2  K-Means算法

k-means 算法的工作过程说明如下:首先从n个数据对象任意选择 k 个对象作为初始聚类中心;而对于所剩下其它对象,则根据它们与这些聚类中心的相似度(距离),分别将它们分配给与其最相似的(聚类中心所代表的)聚类;然后再计算每个所获新聚类的聚类中心(该聚类中所有对象的均值);不断重复这一过程直到标准测度函数开始收敛为止。一般都采用均方差作为标准测度函数. k个聚类具有以下特点:各聚类本身尽可能的紧凑,而各聚类之间尽可能的分开。算法的时间复杂度上界为O(n*k*t), 其中t是迭代次数。

1,从输入的数据点集合中随机选择一个点作为第一个聚类中心。

2,对于数据集中的每一个点x,计算它与最近聚类中心(指已选择的聚类中心)的距离D(x)。

3,选择一个新的数据点作为新的聚类中心,选择的原则是:D(x)较大的点,被选取作为聚类中心的概率较大。

4,重复2和3直到k个聚类中心被选出来。

5,利用这k个初始的聚类中心来运行标准的k-means算法。

k-means算法是一种基于样本间相似性度量的间接聚类方法,属于非监督学习方法。此算法以k为参数,把n 个对象分为k个簇,以使簇内具有较高的相似度,而且簇间的相似度较低。相似度的计算根据一个簇中对象的平均值(被看作簇的重心)来进行。此算法首先随机选择k个对象,每个对象代表一个聚类的质心。对于其余的每一个对象,根据该对象与各聚类质心之间的距离,把它分配到与之最相似的聚类中。然后,计算每个聚类的新质心。重复上述过程,直到准则函数收敛。k-means算法是一种较典型的逐点修改迭代的动态聚类算法,其要点是以误差平方和为准则函数。逐点修改类中心:一个象元样本按某一原则,归属于某一组类后,就要重新计算这个组类的均值,并且以新的均值作为凝聚中心点进行下一次象元素聚类;逐批修改类中心:在全部象元样本按某一组的类中心分类之后,再计算修改各类的均值,作为下一次分类的凝聚中心点。

注意以下几个问题:

(1)初始质心的选取 :选择适当的初始质心是基本kmeans算法的关键步骤。常见的方法是随机的选取初始质心,但是这样簇的质量常常很差。处理选取初始质心问题的一种常用技术是:多次运行,每次使用一组不同的随机初始质心,然后选取具有最小SSE(误差的平方和)的簇集。这种策略简单,但是效果可能不好,这取决于数据集和寻找的簇的个数。第二种有效的方法是:取一个样本,并使用层次聚类技术对它聚类。从层次聚类中提取K个簇,并用这些簇的质心作为初始质心。第三种选择初始质心的方法:随机地选择第一个点,或取所有点的质心作为第一个点。然后,对于每个后继初始质心,选择离已经选取过的初始质心最远的点。使用这种方法,确保了选择的初始质心不仅是随机的,而且是散开的。但是,这种方法可能选中离群点。此外,求离当前初始质心集最远的点开销也非常大。为了克服这个问题,通常该方法用于点样本。由于离群点很少(多了就不是离群点了),它们多半不会在随机样本中出现。计算量也大幅减少。

(3)距离的度量:常用的距离度量方法包括:欧几里得距离和余弦相似度。两者都是评定个体间差异的大小的。欧几里得距离度量会受指标不同单位刻度的影响,所以一般需要先进行标准化,同时距离越大,个体间差异越大;空间向量余弦夹角的相似度度量不会受指标刻度的影响,余弦值落于区间[-1,1],值越大,差异越小。但是针对具体应用,什么情况下使用欧氏距离,什么情况下使用余弦相似度?从几何意义上来说,n维向量空间的一条线段作为底边和原点组成的三角形,其顶角大小是不确定的。也就是说对于两条空间向量,即使两点距离一定,他们的夹角余弦值也可以随意变化。感性的认识,当两用户评分趋势一致时,但是评分值差距很大,余弦相似度倾向给出更优解。举个极端的例子,两用户只对两件商品评分,向量分别为(3,3)和(5,5),这两位用户的认知其实是一样的,但是欧式距离给出的解显然没有余弦值合理。

(4)质心的计算:对于距离度量不管是采用欧式距离还是采用余弦相似度,簇的质心都是其均值,即向量各维取平均即可。对于距离对量采用其它方式时,这个还没研究过。

(5)算法停止条件:一般是目标函数达到最优或者达到最大的迭代次数即可终止。对于不同的距离度量,目标函数往往不同。当采用欧式距离时,目标函数一般为最小化对象到其簇质心的距离的平方和。当采用余弦相似度时,目标函数一般为最大化对象到其簇质心的余弦相似度和。 

(6)空聚类的处理:如果所有的点在指派步骤都未分配到某个簇,就会得到空簇。如果这种情况发生,则需要某种策略来选择一个替补质心,否则的话,平方误差将会偏大。一种方法是选择一个距离当前任何质心最远的点。这将消除当前对总平方误差影响最大的点。另一种方法是从具有最大SSE的簇中选择一个替补的质心。这将分裂簇并降低聚类的总SSE。如果有多个空簇,则该过程重复多次。另外,编程实现时,要注意空簇可能导致的程序bug。

二 K-均值聚类算法的实现

2.1 数据集的准备

所用到的数据如下图所示:

 

2.2主要代码实现

本实验用python进行编程,分为六个函数,分别为:导入数据、计算各点到质心的距离、随机产生初始质心、K-Means算法的实现、实验结果可视化等部分。下图为所用到的K-Means算法的实现。矩阵clusterAssment为m行2列,该矩阵和dataSet的行数相同,行行对应,第一列表示与对应行距离最近的质心下标,第二列表示欧式距离的平方。矩阵centroids为k行2列,表示k个质心的坐标。

代码如下:

 

from numpy import *
import matplotlib.pyplot as plt
#导入数据
def loadDataSet(fileName):
    dataSets = []
    data = []
    f = open(fileName)
    for line in f.readlines():
        curLine = line.strip().split('\t')
        x = float(curLine[0])
        y = float(curLine[1])
        dataSets.append([x,y])
    return mat(dataSets)
#计算距离
def distEclud(vecA, vecB):
    return sqrt(sum(power(vecA - vecB, 2)))
#随机生成k个点作为初始质心
def randCent(dataSet, k):
    n = shape(dataSet)[1] #n是列数
    centroids = mat(zeros((k, n)))
    for j in range(n):
        minJ = min(dataSet[:, j]) #找到第j列最小值
        rangeJ = float(max(dataSet[:, j]) - minJ) #求第j列最大值与最小值的差
        centroids[:, j] = minJ + rangeJ * random.rand(k, 1) #生成k行1列的在(0, 1)之间的随机数矩阵
    return centroids
#K均值聚类算法实现
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) #求同一簇的坐标平均值,axis=0表示按列求均值
    return centroids, clusterAssment
#绘制散点图
def showCluster(dataSet, k, clusterAssment, centroids):
    fig = plt.figure()
    plt.title("K-means")
    ax = fig.add_subplot(111)
    data = []
    # 提取出每个簇的数据
    for cent in range(k): 
        ptsInClust = dataSet[nonzero(clusterAssment[:,0].A==cent)[0]] #获得属于cent簇的数据
        data.append(ptsInClust)
    for cent, c, marker in zip( range(k), ['r', 'g', 'b', 'y'], ['^', 'o', '*', 's'] ): #画出数据点散点图
        ax.scatter(array(data[cent][:, 0]), array(data[cent][:, 1]), s=80, c=c, marker=marker)
    ax.scatter(array(centroids[:, 0]), array(centroids[:, 1]), s=1000, c='black', marker='+', alpha=1) #画出质心点
    ax.set_xlabel('X Label')
    ax.set_ylabel('Y Label')
    plt.show()
def main():
    dat = mat(loadDataSet('Test_data.txt'))  # 读入数据
    center, clust = KMeans(dat, 4)
    randCent(dat,4)
    showCluster(dat, 4, clust, center)
if __name__ == "__main__":
    main()

 

 

 

2.3实验结果

矩阵centroids表示k行2列,为k个质心的坐标,图1为当质心选为4的时候(4行2列的矩阵),不断重复过程更新质心坐标直至达到终止条件,即没有数据点被重新分配给不同的聚类、没有聚类中心再发生变化以及误差平方和达到局部最小。

 

图1

图2为当质心设置为3的时候,所产生的结果:

 

图2

图3为为当质心设置为2的时候,所产生的结果:

 

图3

 

图4为为当质心设置为4的时候,所产生的结果:

图4

三 总结

        通过本次实验,对于K-均值聚类有了更进一步的了解,K-均值算法是最著名的划分聚类算法,由于它的简介和效率使得它成为所有聚类算法中最为广泛使用的。给定一个数据点集合和需要的聚类数目K,K-均值算法根据某个距离函数反复地把数据分入K个聚类中。K-均值算法的主要优势在于它的简介和效率,它的劣势有以下几点:(1)算法只能应用于那些均值能够被定义的数据集上;(2)需要事先指定聚类数目K;(3)对于异常值敏感;(4)对初始选取的质心敏感;(5)不适用于非凸形状的聚类。

    在本次实验中,分别设置质心为2,、3、4来进行试验,观察簇类分布,可以看出质心为3时,是较为适宜的。

 

完整的代码和数据连接:https://download.csdn.net/download/qq_41814556/10535826

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值