目录
聚类分析概念
1.1 为什么聚类
之所以要聚类,是因为当今的数据量剧增(数据爆炸),导致我们检索信息时成本增加。如果可以找到一种计数可以自动分析数据,那么将有效节约资源。
1.2 聚类到底是什么
聚类定义:给定一组无标签样本,按照各样本间的相似度,相似的归为一类,不相似的归为另一类,这种方法称为聚类。
无标签样本:即事先并不知道该样本的类别的样本,与之相对应的是有标签样本(有标签样本中称为分类)。
例如,此时有来自全球的100人,要求按照其人种对其进行聚类或分类。
当我们知道这一百人每一个人的来历时,对其进行上述操作就称为分类,每一个人的人种我们都清晰可知,我们将每一个样本及其标签告诉机器,机器就会训练出相应的分类器,此时的样本集也称为训练集。
当我们用上述100人训练出一个分类器后,接下来我们希望考察它的泛化能力(即应用能力),故我们再随机抽取100人,此时虽然我们仍然明确地知道这100人的来历,但这一次我们并不告诉机器他们的来历(标签),而只输入相应的样本信息,这就是无监督聚类(学习)。机器根据之前在训练集中训练出的分类器对新的样本进行聚类,当输出结果后,我们可以将输出结果和真实情况进行对比,从而检验训练效果,故此时的样本集也称为检验集。
1.3 聚类与分类区别
类别 | 分类 | 聚类 |
---|---|---|
样本情况 | 有标签 | 无标签 |
所属大类 | 监督学习 | 非监督学习 |
目的 | 寻找数据边界 | 寻找数据结构 |
分类(有监督)与聚类(无监督)的区别大致如上表所示。
1.4 相似性与距离聚类
相似性:模式之间有一定的相似性。
对于初学者来说,这个概念较为抽象,下面对于此概念做以简单的解析:
模式:模式可以理解为每一个观测样本。例如,考察某学校学生的平均身高,采用抽样的方法抽查500名同学的身高。这500名同学就是500种模式。
特征:我们要考察的对象’身高‘就是模式的特征,在机器学习与模式识别中,常把模式的特征映射到向量空间中去表达,故特征常被称作’特征向量‘。
特征空间:如上所说,研究模式的特征时,常把特征映射到向量空间中去。而整个模式样本集合的特征向量可以看作某个向量空间中的一些点,这个向量空间就被称为特征空间。
距离聚类:以特征空间中点之间的距离作为聚类依据的聚类方法叫做距离聚类。
1.5 相似性的测度
相似性测量依据:将样本的特征映射到特征空间中得到特征向量,特征向量可以看作特征空间中的一些点,点与点之间的距离则作为相似性的测度。
根据相似性的测度方法,我们可以知道其本质是计算特征向量距离,而选取特征向量则自然牵扯到了维数的问题(即选取多少个特征,选取什么特征等等),下面我们对于此问题做以简要说明:
1.聚类分析有效性的关键在于特征的选取,特征的选取应遵循以下规则:
可分性好:同一群样本密集,不同群的样本尽可能远。
2.特征向量分量个数(维数)并不是越多越好。我们对于样本特征的选取,常常取决于我们的分类目的。对于样本特征过多地关注往往会造成聚类的错误以及计算量的负担。比如,我们现在获得10个水果,要求按照颜色对其进行聚类。我们的分类目的是将其颜色分开,如若我们关注不必要的特征。例如‘形状’,则可以会犯将橘子和西瓜分为一类的荒谬错误。
3.特征表示时要注意量纲一致。
特征相似度测度与聚类准则
2.1 特征相似度测度
前面以及提到相似性的测度是特征空间中点与点之间的距离,而距离有很多表述方法,下面介绍几种常见的距离测度:
(a) 欧氏距离
设
,
在X,Y量纲一致的前提下,有:
即为样本间对应特征的欧式距离
(b) 马氏距离
马氏距离定义如下:
其中 为协方差矩阵
对于马氏距离,我们做以下几点说明:
1.马氏距离则不要求数据量纲一致,也就是说,马氏距离与原始数据的测量单位无关(因为单位已经被协方差矩阵消掉)。此性质相对于欧氏距离为我们提供了很大的便捷。实际上,我们的数据来源非常广泛,而每个人的测量习惯不同,导致其使用的测量单位也往往不一样。而马氏距离的构造很好地冲消了这一点的影响。
2.马氏距离削弱了相关性过强的变量的影响,在欧式距离中,如果某两个变量相关性过强,则会造成巨大的影响,这就屏蔽了其它变量的影响,容易对我们造成误导。而马氏距离则不然,对于相关性强的变量,协方差矩阵中对其协方差取倒数,一定程度上削弱了过强的影响,也可以让我们更加全面地去考察样本间的相关性。
3.当马氏距离中的协方差矩阵为单位阵时,其等于欧氏距离。
(c) 明氏距离
明氏距离定义如下:
其中,
为第i个样本和第j的样本的第k个分量。
当m=2时,此时的明氏距离就是欧氏距离。
当m=1时,此时的马氏距离就是街坊距离(city block)。
(d) 角度相似性函数
角度相似性函数定义如下:
可以看到,上述公式事实上就是反应模式向量x,z间夹角的余弦值。表征的更多是模式间方向的相似性。关于余弦相似度的详解,读者可以查看我的另一个博客“机器学习——余弦相似度”。
(e)Tanimoto测度
定义如下:
也就是表示了x,z中共有的特征数目占两者一共的特征数目百分比。
与前不同,x,z用二分量表示。0表示不具有某种特征,1表示具有某种特征。
2.2 聚类准则
1.试探方法
经验,直观,但也易出错。
2.聚类准则法
由于聚类是将样本进行分类以使类别间可分离性为最大,因此聚类准则应是反映类别间相似性或分离性的函数。而类别又由一个个样本组成,故类别间相似性和样本的相似性及可分离性息息相关。故可以考虑定义一个函数,其以模式样本集{x}和模式类别S为自变量,从而将问题转换为求解函数的最优化问题。此函数则称为聚类准则函数,表达式如下:
其中,{x}为模式样本集
为模式类别
为样本均值向量
分级聚类法
分级聚类法基本思路:根据类内或类间的相似度测量,依次分类。
其算法步骤大致如下:
简单说明:其中k为初始类数,假设初始有n个样本,则尚未开始聚类前每一个样本都是一个类别,故第一步有k=n(n为样本数)。而后通过计算类间距离,将类间距离最小的两个类合并为一个类,如此迭代,直至满足停止条件。
上述说明自然地引出了两个问题:如何度量距离?如何判定是否满足停止条件?下面我们逐一进行说明。
1.如何度量距离
对于距离,我们看到,在此算法中既有类内诸多样本点间的距离,也有各类间的类间距离。
a) 类内距离(样本间距离)
类内距离的度量在全面我们已经提到,即相似性测度里的几种距离测度,而具体选用哪种测度,须依据实际情况而定。
b)类间距离
类间距离的测量标准常有以下三种:
1.最近领域法则
即选取两类间距离最近的样本作为两类的距离,公式表达为:
采用最近领域法则一个很明显的缺点就是对于噪声过于敏感。
2.最远领域法则
与最近领域法则恰好相反,最远领域法则选取两类间距离最远的样本作为两类的距离,公式表达为:
3.平均领域法则
平均领域法则即计算两类间样本的平均距离作为类间距离,公式表达为:
平均领域法则由于计算了多个样本间距离的平均值,故其容错性较好,对于噪声的抵抗能力较强。但计算量相对前两者有了明显的增加。
我们该如何选择类间距离测度?
这取决于我们对于数据的了解程度,如果我们实现知道数据的可分性非常好并且类内样本分布紧凑,那么不论是哪种方法都可以得到不错的分类结果。如果我们样本的可分性较差,类间距离较小,那么通常采用平均领域法则。
2.如何判定是否满足停止条件
停止条件可以有很多种形式,满足其中一种形式即可停止聚类,下面给出常见的几种停止条件:
a) 给定聚类数k,即希望最后聚为k类。
b) 给定最大允许的类间距离门限。即若
,则停止聚类。
这种思想很好理解,当类间距离过大时,有可能出现了将两类聚为了一类的情况。
c)当上一次聚类与这一次聚类的类间距离变化很大,即类间距离剧增时,停止聚类,此时表明有可能将原本的两类聚为了一类。
对分级聚类法的基础知识有一定了解后,接下来我们给出算法的实现(基于Python):
def hcluster(rows,distance=pearson):
distances={}
currentclustid=-1
# Clusters are initially just the rows
clust=[bicluster(rows[i],id=i) for i in range(len(rows))]
while len(clust)>1:
lowestpair=(0,1)
closest=distance(clust[0].vec,clust[1].vec)
print "closest",closest
# loop through every pair looking for the smallest distance
for i in range(len(clust)):
for j in range(i+1,len(clust)):
# distances is the cache of distance calculations
if (clust[i].id,clust[j].id) not in distances:
distances[(clust[i].id,clust[j].id)]=distance(clust[i].vec,clust[j].vec)
d=distances[(clust[i].id,clust[j].id)]
if d<closest:
closest=d
lowestpair=(i,j)
# calculate the average of the two clusters
mergevec=[
(clust[lowestpair[0]].vec[i]+clust[lowestpair[1]].vec[i])/2.0
for i in range(len(clust[0].vec))]
# create the new cluster
newcluster=bicluster(mergevec,left=clust[lowestpair[0]],
right=clust[lowestpair[1]],
distance=closest,id=currentclustid)
# cluster ids that weren't in the original set are negative
currentclustid-=1
del clust[lowestpair[1]]
del clust[lowestpair[0]]
clust.append(newcluster)
return clust[0]