首页 > 代码库 > 聚类算法(clustering)

聚类算法(clustering)

转自http://blog.csdn.net/JasonDing1354/article/details/49806017?locationNum=2&fps=1

 

1 聚类分析基本概念

聚类分析将数据划分成有意义或有用的簇。如果目标是划分成有意义的组,则簇应当捕获数据的自然结构。 
聚类分析是一种分类的多元统计分析方法。按照个体或样品的特征将它们分类,使同一类别内的个体具有尽可能高的同质性(homogeneity),而类别之间则应具有尽可能高的异质性(heterogeneity)。 
聚类是研究数据间逻辑上或物理上的相互关系的技术,其分析结果不仅可以揭示数据间的内在联系与区别,还可以为进一步的数据分析与知识发现提供重要依据。它 是数据挖掘技术中的重要组成部分。作为统计学的重要研究内容之一,聚类分析具有坚实的理论基础,并形成了系统的方法学体系

2 聚类分析的应用

聚类分析是洞察数据分布的独立工具,也可以作为其他算法预处理或者中间处理环节的方法。 
一般而言,可分为以下几个方面: 
(1)其他数据挖掘任务的关键中间环节:用于构建数据概要,用于分类、模式识别、假设生成和测试;用于异常检测,检测远离群簇的点。 
(2)数据摘要、数据压缩、数据降维:例如图像处理中的矢量量化技术。创建一个包含所有簇原型的表,即每个原型赋予一个整数值,作为它在表中的索引。每个对象用与它所在簇相关联的原型的索引表示。 
(3)协同过滤:用于推荐系统和用户细分。 
(4)动态趋势检测:对流数据进行聚类,检测动态趋势和模式。 
(5)用于多媒体数据、生物数据、社交网络数据的应用

举例来说,在商务上,聚类能帮助市场分析人员从客户基本库中发现不同的客户群,并且用不同的购买模式来刻画不同的消费群体的特征。在生物学上,聚类能用于帮助推导植物和动物的种类,基因和蛋白质的分类,获得对种群中固定结构的认识。聚类在地球观测数据中相似地区的确定,根据房屋的类型、价值和位置对一个城市中房屋的分类发挥作用。聚类也能用来对web上的文档进行分类,以发现有用的信息。聚类分析能作为一种独立的工具来获得数据分布的情况,观察每个簇的特点,并对某些特定的节点进一步分析。

3 聚类算法的分类

聚类分析的算法可以分为划分法(Partitioning Methods)、层次法(Hierarchical Methods)、基于密度的方法(density-based methods)、基于网格的方法(grid-based methods)、基于模型的方法(Model-Based Methods)。

3.1 基于距离的方法

划分算法和层次算法可以看做是基于距离的聚类算法。 
划分算法(partitioning method)是简单地将数据对象划分成不重叠的子集(簇),使得每个数据对象恰在一个子集中。 
给定一个有N个元组或者纪录的数据集,分裂法将构造K个分组,每一个分组就代表一个聚类,K

3.2 基于密度的方法

绝大多数划分方法基于对象之间的距离进行聚类,这样的方法只能发现球状的类,而在发现任意形状的类上有困难。因此,出现了基于密度的聚类方法,其主要思想是:只要邻近区域的密度(对象或数据点的数目)超过某个阈值,就继续聚类。也就是说,对给定类中的每个数据点,在一个给定范围的区域内必须至少包含某个数目的点。这样的方法可以过滤“噪声”数据,发现任意形状的类。但算法计算复杂度高,一般为O(n^2),对于密度分布不均的数据集,往往得不到满意的聚类结果。 
其代表算法有DBSCAN、OPTICS和DENCLUE等。

3.3 基于网格的方法

基于网格的方法把对象空间量化为有限数目的单元,形成一个网格结构。所有的聚类操作都在这个网格结构(即量化空间)上进行。这种方法的主要优点是它的处理 速度很快,其处理速度独立于数据对象的数目,只与量化空间中每一维的单元数目有关。但这种算法效率的提高是以聚类结果的精确性为代价的。 
它的代表算法有STING、CLIQUE、WAVE-CLUSTER等。

3.4 基于概率和生成模型的方法

基于模型的聚类算法为每簇假定了一个模型,寻找数据对给定模型的最佳拟合。一个基于模型的算法可能通过构建反应数据点空间分布的密度函数来定位聚类。它也基于标准的统计数字自动决定聚类的数目,过滤噪声数据或孤立点,从而产生健壮的聚类方法。基于模型的聚类试图优化给定的数据和某些数据模型之间的适应性。 这样的方法经常是基于这样的假设:数据是根据潜在的概率分布生成的。 
基于模型的方法主要有两类:统计学方法和网络神经方法。其中,统计学方法有COBWEB算法,网络神经方法有SOM算法

4 对聚类分析的要求

4.1 聚类质量

处理不同类型属性的能力:许多算法被设计用来聚类数值类型的数据。但是,应用可能要求聚类其他类型的数据,如二元类型(binary),分类/标称类型(categorical/nominal),序数型(ordinal)数据,或者这些数据类型的混合。

发现任意形态的群簇:许多聚类算法基于欧几里得或者曼哈顿距离度量来决定聚类。基于这样的距离度量的算法趋向于发现具有相近尺度和密度的球状簇。但是,一个簇可能是任意形状的。提出能发现任意形状簇的算法是很重要的。

处理噪声的能力:绝大多数现实中的数据库都包含了孤立点,缺失,或者错误的数据。一些聚类算法对于这样的数据敏感,可能导致低质量的聚类结果。

4.2 可伸缩性

许多聚类算法在小于200个数据对象的小数据集合上工作得很好;但是,一个大规模数据库可能包含几百万个对象,在这样的大数据集合样本上进行聚类可能会导致有偏的结果。我们需要具有高度可伸缩性的聚类算法 
可伸缩性的聚类算法要求算法对所有数据进行聚类,能够处理好高维数据,可以对流数据进行聚类,算法对数据输入顺序不敏感。

4.3 可解释性和可用性

用户希望聚类结果是可解释的,可理解的,和可用的。也就是说,聚类可能需要和特定的语义解释和应用相联系。

 

详细解释主要的算法:K-Means

转自http://blog.csdn.net/u012162613/article/details/47811235?locationNum=1&fps=1

1.聚类分析

1.0 概念

聚类分析简称聚类(clustering),是一个把数据集划分成子集的过程,每一个子集是一个簇(cluster),使得簇中的样本彼此相似,但与其他簇中的样本不相似。

聚类分析不需要事先知道样本的类别,甚至不用知道类别个数,因此它是一种无监督的学习算法,一般用于数据探索,比如群组发现和离群点检测,还可以作为其他算法的预处理步骤。

下面的动图展示的是一个聚类过程,感受一下:

技术分享

1.1 基本聚类方法

主要的聚类算法一般可以划分为以下几类:

方法一般特点
划分方法 1.发现球形互斥的簇 2.基于距离 3.可用均值或中心点代表簇中心 4.对中小规模数据有效
层次方法 1.聚类是一个层次分解 2.不能纠正错误的合并或划分 3.可以集成其他技术
基于密度的方法 1.可以发现任意形状的簇 2.簇是对象空间中被低密度区域分隔的稠密区域 3.簇密度 4.可能过滤离群点
基于网格的方法 1.使用一种多分辨率网格数据结构 2.快速处理


上面的内容节选自韩家炜的《数据挖掘》,该书中的第十和第十一章对聚类算法进行了详细的介绍。等我详细学习后再对聚类分析做个总结,这篇文章则把重点放在简单的Kmeans算法上,Kmeans算法属于上面分类中的划分方法。


2.Kmeans算法思想

2.0 算法步骤

Kmeans算法(k均值算法)是一种简单的聚类算法,属于划分式聚类算法,当给定一个数据集D时,Kmeans算法的步骤如下:

选择K个点作为初始质心(随机产生或者从D中选取)  
repeat  
    将每个点分配到最近的质心,形成K个簇  
    重新计算每个簇的质心  
until 簇不发生变化或达到最大迭代次数  

若n是样本数,m是特征维数,k是簇数,t是迭代次数,则Kmeans算法的时间复杂度为O(tknm),与样本数量线性相关,所以在处理大数据集合时比较高效,伸缩性好。空间复杂度为O((n+k)*m)。

Kmens算法虽然一目了然,但算法实现过程中涉及到的细节也不少,下面逐一介绍。

2.0 k值选取

k的值是用户指定的,表示需要得到的簇的数目。在运用Kmeans算法时,我们一般不知道数据的分布情况,不可能知道数据的集群数目,所以一般通过枚举来确定k的值。另外,在实际应用中,由于Kmean一般作为数据预处理,或者用于辅助分类贴标签,所以k一般不会设置很大。

2.1 初始质心的选取

Kmeans算法对初始质心的选取比较敏感,选取不同的质心,往往会得到不同的结果。初始质心的选取方法,常用以下两种的简单方法:一种是随机选取,一种是用户指定。 
需要注意的是,无论是随机选取还是用户指定,质心都尽量不要超过原始数据的边界,即质心每一维度上的值要落在原始数据集每一维度的最小与最大值之间。

2.2 距离度量方法

距离度量方法(或者说相似性度量方法)有很多种,常用的有欧氏距离,余弦相似度,街区距离,汉明距离等等。在Kmeans算法中,一般采用欧氏距离计算两个点的距离,欧氏距离如下: 

技术分享
 
技术分享

举这个例子是为了说明,当原始数据中各个维度的数量级不同时,它们对结果的影响也随之不同,那些数量级太小的维度,对于结果几乎没产生任何影响。比如所举的例子中的第二个维度的0.1,0.2,与第一个维度1000的数量级相差了一万倍。

为了赋予数据每个维度同等的重要性,我们在运用欧氏距离时,必须先对数据进行规范化,比如将每个维度都缩放到[0,1]之间。

2.3 质心的计算

在Kmeans算法中,将簇中所有样本的均值作为该簇的质心。这也是Kmeans名字的由来吧。

2.4 算法停止条件

在两种情况下算法应该停止:一种是达到了指定的最大迭代次数,一种是算法已经收敛,即各个簇的质心不再发生变化。关于算法的收敛,在2.5部分讨论。

2.5 代价函数与算法收敛

Kmeans算法的代价函数比较简单,就是每个样本点与其所属质心的距离的平方和(误差平方和,Sum of Squared Error,简称SSE):

 技术分享

与其他机器学习算法一样,我们要最小化这个代价函数,但这个函数没有解析解,所以只能通过迭代求解的方法来逼近最优解(这一点也和众多机器学习算法一样吧)。所以你再看看算法步骤,其实就是一个迭代过程。

由于代价函数(SSE)是非凸函数,所以在运用Kmeans算法时,不能保证收敛到一个全局的最优解,我们得到的一般是一个局部的最优解。

因此,为了取得比较好的效果,我们一般会多跑几次算法(用不同的初始质心),得到多个局部最优解,比较它们的SSE,选取SSE最小的那个。

3.Kmeans算法实现

3.1 代码

这是采用Python编写,基于数值计算库Numpy实现的Kmeans算法,参考了Scikit Learn的设计,将Kmeans封装成一个class,对于代码简要说明如下,具体的可以在这里查看:代码链接。


class KMeans(object):

    def __init__(self,n_clusters=5,initCent=‘random‘,max_iter=300):
        #n_clusters表示聚类个数,相当于k
        #initCent表示质心的初始化方式,可以设为‘random‘或指定一个数组
        #max_iter表示最大的迭代次数

    def _distEclud(self, vecA, vecB):
        #计算两点的欧式距离

    def _randCent(self, X, k):
        #随机选取k个质心,必须在数据集的边界内

    def fit(self, X):
        #调用fit方法,对数据集X聚类
        #聚类完后将得到质心self.centroids,簇分配结果self.clusterAssment       

    def predict(self,X):
        #根据聚类结果,预测新输入数据所属的族
        #其实就是计算每个点与各个质心self.centroids的距离

3.2 实例

下面看一个简单的例子,首先是数据集的准备,文章开头展示的图片来自于这份数据data.pkl,是经典的手写数字MNIST数据库,我从中选取1000张(包括0~9共十种数字),用t_sne降到了2维(为了可视化)。

首先,加载数据集:

import cPickle
X,y = cPickle.load(open(‘data.pkl‘,‘r‘))  #X和y都是numpy.ndarray类型
X.shape  #输出(1000,2)
y.shape  #输出(1000,)对应每个样本的真实标签

对该数据集进行聚类分析,聚类个数设置为10(因为有十种数字),质心初始化方式为随机初始化,最大迭代次数设置为100。并利用matplotlib画出聚类结果:

import numpy as np
import matplotlib.pyplot as plt
from kmeans import KMeans
clf = KMeans(n_clusters=10,initCent=‘random‘,max_iter=100)
clf.fit(X)
cents = clf.centroids#质心
labels = clf.labels#样本点被分配到的簇的索引
sse = clf.sse
#画出聚类结果,每一类用一种颜色
colors = [‘b‘,‘g‘,‘r‘,‘k‘,‘c‘,‘m‘,‘y‘,‘#e24fff‘,‘#524C90‘,‘#845868‘]
n_clusters = 10
for i in range(n_clusters):
    index = np.nonzero(labels==i)[0]
    x0 = X[index,0]
    x1 = X[index,1]
    y_i = y[index]
    for j in range(len(x0)):
        plt.text(x0[j],x1[j],str(int(y_i[j])),color=colors[i],                fontdict={‘weight‘: ‘bold‘, ‘size‘: 9})
    plt.scatter(cents[i,0],cents[i,1],marker=‘x‘,color=colors[i],linewidths=12)
plt.title("SSE={:.2f}".format(sse))
plt.axis([-30,30,-30,30])
plt.show()

得到的结果如下,可见效果并不好,5和8,3和9都被混为一类:

技术分享

而且,不改动上面的代码,每一次得到的结果也不一样,这是因为Kmeans聚类对于初始质心的选取是敏感的,而上面的代码中我们采用随机初始化质心的方式。当然,我们也可以采取指定初始质心的方式,只需要改一行代码:

clf = KMeans(n_clusters=10,initCent=X[0:10],max_iter=100)

4.二分Kmeans算法

二分Kmeans算法(bisecting Kmeans)是为了克服Kmeans算法收敛于局部最小值的问题而提出的。该算法首先将所有点作为一个簇,然后将该簇一分为二。之后选择其中一个簇继续划分,选择哪一个簇进行划分取决于对其划分是否可以最大程度降低SSE的值,上述过程不断迭代,直到得到用户指定的簇数目为止。算法步骤如下:

将所有数据点看成一个簇

当簇数目小于k时

       对每一个簇

              计算总误差(sse_origin)

              在给定的簇上面进行k-均值聚类(k=2)

              计算将该簇一分为二后的总误差(sse_new)

       选择使得误差(sse_new)最小的那个簇进行划分操作

根据这个步骤,不难写出二分Kmeans算法的代码,其使用方法如下:

import numpy as np
import matplotlib.pyplot as plt
from kmeans import biKMeans
n_clusters = 10
clf = biKMeans(n_clusters)
clf.fit(X)
cents = clf.centroids
labels = clf.labels
sse = clf.sse
#画出聚类结果,每一类用一种颜色
colors = [‘b‘,‘g‘,‘r‘,‘k‘,‘c‘,‘m‘,‘y‘,‘#e24fff‘,‘#524C90‘,‘#845868‘]
for i in range(n_clusters):
    index = np.nonzero(labels==i)[0]
    x0 = X[index,0]
    x1 = X[index,1]
    y_i = y[index]
    for j in range(len(x0)):
        plt.text(x0[j],x1[j],str(int(y_i[j])),color=colors[i],                fontdict={‘weight‘: ‘bold‘, ‘size‘: 9})
    plt.scatter(cents[i,0],cents[i,1],marker=‘x‘,color=colors[i],linewidths=12)
plt.title("SSE={:.2f}".format(sse))
plt.axis([-30,30,-30,30])
plt.show()

得到下图,可以发现效果也并不是特别好,并且多次运行上面的代码,结果也是不一样的,这是因为二分Kmeans算法在“二分”的时候,采取的也是随机初始化质心的方式。

技术分享

相关的其他聚类算法,请参考以下博客:

http://blog.csdn.net/abcjennifer/article/details/8170687

http://blog.csdn.net/zhoubl668/article/details/6639801?locationNum=3&fps=1

http://blog.csdn.net/zhoubl668/article/details/7945678?locationNum=5&fps=1

http://blog.csdn.net/zhoubl668/article/details/7881313?locationNum=13&fps=1

以及大神之作

http://blog.pluskid.org/?page_id=78

 

聚类算法(clustering)