常用聚类以及聚类的度量指标:
一年前需要用聚类算法时,自己从一些sklearn文档和博客粗略整理了一些相关的知识,记录在电子笔记里备忘,现在发到网上,当时就整理的就很乱,以后有空慢慢把内容整理、完善,用作备忘。之前把电影标签信息的聚类结果作为隐式反馈放进SVD++中去训练,里面有两个小例子
外部度量:
利用条件熵定义的同质性度量:
sklearn.metrics.homogeneity_score:每一个聚出的类仅包含一个类别的程度度量。
sklearn.metrics.completeness:每一个类别被指向相同聚出的类的程度度量。
sklearn.metrics.v_measure_score:上面两者的一种折衷:
v = 2 * (homogeneity * completeness) / (homogeneity + completeness)
可以作为聚类结果的一种度量。
sklearn.metrics.adjusted_rand_score:调整兰德系数。
ARI取值范围为[-1,1],从广义的角度来讲,ARI衡量的是两个数据分布的吻合程度
sklearn.metrics.adjusted_mutual_info_score:调整互信息。
利用基于互信息的方法来衡量聚类效果需要实际类别信息,MI与NMI取值范围为[0,1],AMI取值范围为[-1,1]。
在真实的分群label不知道的情况下(内部度量):
Calinski-Harabaz Index:
在scikit-learn中, Calinski-Harabasz Index对应的方法是metrics.calinski_harabaz_score.
CH指标通过计算类中各点与类中心的距离平方和来度量类内的紧密度,通过计算各类中心点与数据集中心点距离平方和来度量数据集的分离度,CH指标由分离度与紧密度的比值得到。从而,CH越大代表着类自身越紧密,类与类之间越分散,即更优的聚类结果。
sklearn.metrics.silhouette_score:轮廓系数
silhouette_sample
对于一个样本点(b - a)/max(a, b)
a平均类内距离,b样本点到与其最近的非此类的距离。
silihouette_score返回的是所有样本的该值,取值范围为[-1,1]。
这些度量均是越大越好
sklearn kmeans,聚类算法kmeans:
流程伪代码:创建K个点作为起始质心(通常是随机)
当任意一个点的簇分配结果发生改变时
对数据集中的每个数据点
对每个质心
计算质心与数据点之间的距离
将数据点分配到最近的簇
对每个簇,计算簇中所有点的均值并将均值作为质心
sklearn中的K-means
K-means算法应该算是最常见的聚类算法,该算法的目的是选择出质心,使得各个聚类内部的inertia值最小化,计算方法如下:
inertia可以被认为是类内聚合度的一种度量方式,这种度量方式的主要缺点是:
(1)inertia假设数据内的聚类都是凸的并且各向同性( convex and isotropic),
各项同性是指在数据的属性在不同方向上是相同的。数据并不是总能够满足这些前提假设的,
所以当数据事细长簇的聚类,或者不规则形状的流形时,K-means算法的效果不理想。
(2)inertia不是一种归一化度量方式。一般来说,inertia值越小,说明聚类效果越好。
但是在高维空间中,欧式距离的值可能会呈现迅速增长的趋势,所以在进行K-means之前首先进行降维操作,如PCA等,可以解决高维空间中inertia快速增长的问题,也有主意提高计算速度。
K-means算法可以在足够长的时间内收敛,但有可能收敛到一个局部最小值。
聚类的结果高度依赖质心的初始化,因此在计算过程中,采取的措施是进行不止一次的聚类,每次都初始化不同的质心。
sklearn中可以通过设置参数init='kmeans++'来采取k-means++初始化方案,
即初始化的质心相互之间距离很远,这种方式相比于随机初始质心,能够取得更好的效果。
另外,sklearn中可以通过参数n_job,使得K-means采用并行计算的方式。
##sklearn 中K-means的主要参数:
1) n_clusters: 设定的k值
2)max_iter: 最大的迭代次数,一般如果是凸数据集的话可以不管这个值,如果数据集不是凸的,可能很难收敛,此时可以指定最大的迭代次数让算法可以及时退出循环。
3)n_init:用不同的初始化质心运行算法的次数。由于K-Means是结果受初始值影响的局部最优的迭代算法,因此需要多跑几次以选择一个较好的聚类效果,默认是10。如果你的k值较大,则可以适当增大这个值。
4)init: 即初始值选择的方式,可以为完全随机选择'random',优化过的'k-means++'或者自己指定初始化的k个质心。一般建议使用默认的'k-means++'。
5)algorithm:有“auto”, “full” or “elkan”三种选择。"full"就是我们传统的K-Means算法, “elkan”elkan K-Means算法。默认的"auto"则会根据数据值是否是稀疏的,来决定如何选择"full"和“elkan”。一般来说建议直接用默认的"auto"
sklearn 中K-means的主要方法
聚类的中心
print clf.cluster_centers_
每个样本所属的簇
print clf.labels_
用来评估簇的个数是否合适,距离越小说明簇分的越好,选取临界点的簇个数
print clf.inertia_
Sum of distances of samples to their closest cluster center.
两个小例子(很久以前弄的,写得比较简略比较乱,有空再改,数据是movielen中的电影标签信息):
例1:
kmeans_model = KMeans(n_clusters = 10, random_state = 1,init='k-means++')
pred = kmeans_model.fit_predict(matrix)
print pred
print kmeans_model.cluster_centers_ #聚类的中心
print kmeans_model.labels_#每个样本所属的簇
print kmeans_model.inertia_
例2,在区间[2,200]上遍历k,并生成两个聚类内部评价指标CH分、轮廓系数以及kmeans自带inertia分和对应的k值的图片来选择k:
i = []
y_silhouette_score = []
inertia_score = []
calinskiharabaz_score = []
for k in range(2,201):
kmeans_model = KMeans(n_clusters = k, random_state = 1,init='k-means++')
pred = kmeans_model.fit_predict(matrix)
silhouettescore = silhouette_score(matrix, pred)
print "silhouette_score for cluster '{}'".format(k)
print silhouettescore
calinskiharabazscore = calinski_harabaz_score(matrix, pred)
print "calinski_harabaz_score '{}'".format(k)
print calinskiharabazscore
i.append( k )
y_silhouette_score.append( silhouettescore )
inertia_score.append(kmeans_model.inertia_)
calinskiharabaz_score.append( calinskiharabazscore )
print "kmeans_model.inertia_score for cluster '{}'".format(k)
print kmeans_model.inertia_
#转成字典方便查找
#dict_silhouette = dict(zip( i,y_silhouette_score))
#dict_inertia_score = dict(zip( i,inertia_score))
#dict_calinskiharabaz_score = dict(zip( i, calinskiharabaz_score))
plt.figure()
plt.plot(i,y_silhouette_score)
plt.xlabel("kmeans-k")
plt.ylabel("silhouette_score")
plt.title("matrix")
plt.figure()
plt.plot(i,inertia_score)
plt.xlabel("kmeans-k")
plt.ylabel("inertia_score(sum of squared)")
plt.title("matrix")
plt.figure()
plt.plot(i,calinskiharabaz_score)
plt.xlabel("kmeans-k")
plt.ylabel("calinski_harabaz_score")
plt.title("matrix")
calinskiharabaz_score.png
silhouette_score.png
inertia.png
Affinity Propagation(AP聚类算法)
其中两点相似度s(i, j)的度量默认采用负欧氏距离。
sklearn.cluster.AffinityPropagation
有参数preference(设定每一个点的偏好,将偏好于跟其他节点的相似性进行比较,选择
高的作为exmplar,未设定则使用所有相似性的中位数)、damping (阻尼系数,
利用阻尼系数与1-阻尼系数对r 及 a进行有关迭代步数的凸组合,使得算法收敛
default 0.5 可以取值与[0.5, 1])
cluster_centers_indices_:中心样本的指标。
AP算法的主要思想是通过数据点两两之间传递的信息进行聚类。
该算法的主要优点是能够自主计算聚类的数目,而不用人为制定类的数目。
其缺点是计算复杂度较大 ,计算时间长同时空间复杂度大,
因此该算法适合对数据量不大的问题进行聚类分析。
数据点之间传递的信息包括两个,吸引度(responsibility)r(i,k)和归属度(availability)a(i,k)。
吸引度r(i,k)度量的是质心k应当作为点i的质心的程度,
归属度a(i,k)度量的是点i应当选择质心k作为其质心的程度。
其中t是迭代的次数,λ是阻尼因子,其值介于[0,1],在sklearn.cluster.AffinityPropagation中通过参数damping进行设置。
每次更新完矩阵后,就可以为每个数据点分配质心,分配方式?是针对数据点i,遍历所有数据点k(包括其自身),
找到一个k使得r(i,k)+a(i,k)的值最大,则点k就是点i所属的质心,迭代这个过程直至收敛。
所谓收敛就是所有点所属的质心不再变化
Mean Shift
首先说明不引入核函数时的情况。
算法大致流程为:随机选取一个点作为球心,以一定半径画一个高维球(数据可能是高维的),
在这个球范围内的点都是这个球心的邻居。这些邻居相对于球心都存在一个偏移向量,
将这些向量相加求和再平均,就得到一个mean shift,起点在原球心,重点在球内的其他位置。
以mean shift的重点作为新的球心,重复上述过程直至收敛。
这个计算过程中,高维球内的点,无论其距离球心距离多远,对于mean shift的计算权重是一样的。
为了改善这种情况,在迭代计算mean shift的过程中引入了核函数
sklearn中相关实现是sklearn.cluster.MeanShift。
层次聚类说明
sklearn中实现的是自底向上的层次聚类,实现方法是sklearn.cluster.AgglomerativeClustering。
初始时,所有点各自单独成为一类,然后采取某种度量方法将相近的类进行合并,并且度量方法有多种选择。
合并的过程可以构成一个树结构,其根节点就是所有数据的集合,叶子节点就是各条单一数据。
sklearn.cluster.AgglomerativeClustering中可以通过参数linkage选择不同的度量方法,用来度量两个类之间的距离,
可选参数有ward,complete,average三个。
ward:选择这样的两个类进行合并,合并后的类的离差平方和最小。
complete:两个类的聚类被定义为类内数据的最大距离,即分属两个类的距离最远的两个点的距离。
选择两个类进行合并时,从现有的类中找到两个类使得这个值最小,就合并这两个类。
average:两个类内数据两两之间距离的平均值作为两个类的距离。
同样的,从现有的类中找到两个类使得这个值最小,就合并这两个类。
Agglomerative cluster有一个缺点,就是rich get richer现象,
这可能导致聚类结果得到的类的大小不均衡。
从这个角度考虑,complete策略效果最差,ward得到的类的大小最为均衡。
但是在ward策略下,affinity参数只能是“euclidean”,即欧式距离。
如果在欧氏距离不适用的环境中,average is a good alternative。
另外还应该注意参数affinity,这个参数设置的是计算两个点之间距离时采用的策略,
注意和参数linkage区分,linkage设置的是衡量两个类之间距离时采用的策略,
而点之间的距离衡量是类之间距离衡量的基础。
affinity的可选数值包括 “euclidean”, “l1”, “l2”, “manhattan”, “cosine”,
‘precomputed’. If linkage is “ward”, only “euclidean” is accepted.
DBSCAN
DBSCAN算法的主要思想是,认为密度稠密的区域是一个聚类,各个聚类是被密度稀疏的区域划分开来的。
也就是说,密度稀疏的区域构成了各个聚类之间的划分界限。与K-means等算法相比,该算法的主要优点包括:可以自主计算聚类的数目,不需要认为指定;不要求类的形状是凸的,可以是任意形状的。
DBSCAN中包含的几个关键概念包括core sample,non-core sample,min_sample,eps。
core samle是指,在该数据点周围eps范围内,至少包含min_sample个其他数据点,则该点是core sample,
这些数据点称为core sample的邻居。与之对应的,non-sample是该点周围eps范围内,所包含的数据点个数少于min_sample个。从定义可知,core sample是位于密度稠密区域的点。
一个聚类就是一个core sample的集合,这个集合的构建过程是一个递归的构成。
首先,找到任意个core sample,然后从它的邻居中找到core sample,
接着递归的从这些邻居中的core sample的邻居中继续找core sample。
要注意core sample的邻居中不仅有其他core sample,也有一些non-core smaple,
也正是因为这个原因,聚类集合中也包含少量的non-core sample,它们是聚类中core sample的邻居,
但自己不是core sample。这些non-core sample构成了边界。
在确定了如何通过单一core sample找到了一个聚类后,下面描述DBSCAN算法的整个流程。
首先,扫描数据集找到任意一个core sample,以此core sample为起点,按照上一段描述的方法进行扩充,确定一个聚类。然后,再次扫描数据集,找到任意一个不属于以确定类别的core sample,重复扩充过程,再次确定一个聚类。
迭代这个过程,直至数据集中不再包含有core sample。
这也是为什么DBSCAN不用认为指定聚类数目的原因。
DBSCAN算法包含一定的非确定性。数据中的core sample总是会被分配到相同的聚类中的,哪怕在统一数据集上多次运行DBSCAN。其不确定性主要体现在non-core sample的分配上。
一个non-core sample可能同时是两个core sample的邻居,而这两个core sample隶属于不同的聚类。
DBSCAN中,这个non-core sample会被分配给首先生成的那个聚类,而哪个聚类先生成是随机的。
sklearn中DBSCAN的实现中,邻居的确定使用的ball tree和kd-tree思想,这就避免了计算距离矩阵。