聚类效果评估——轮廓系数(Silhouette Coefficient)附Python代码

前言

在机器学习中,无监督学习算法中聚类算法算作相对重要的一部分算法。也常在低资源和无标注的情况下使用。
其中KMeans作为聚类算法中的一种,充当着重要的角色。由于其思想较为简单,易于理解和方便实现。所以经常被用来做数据的处理,在NLP领域常被用于文本聚类以及文本类别挖掘等方向。

但是KMeans算法有一个致命的缺点就是,如何选择K值。K值的选择至关重要,选择的好可以有较好的聚类效果。

通常情况下,K值的选择人们会根据先验的知识给定一个估计的值,或者是利用Canopy算法计算出一个大致的K值。更多的情况下,还是利用后验的方式进行K值的选择。也就是在给定K的范围[a,b]下,对不同的K值分别进行聚类操作,最终利用聚类效果的评价指标,来给出相应的最优聚类结果。这种评价聚类结果效果的指标有:误差平方和(Sum of the Squared Errors, SSE),轮廓系数(Silhouette Coefficient)和CH指标(Calinski-Harabaz)。

是什么?

轮廓系数,是用于评价聚类效果好坏的一种指标。可以理解为描述聚类后各个类别的轮廓清晰度的指标。其包含有两种因素——内聚度和分离度。

内聚度可以理解为反映一个样本点与类内元素的紧密程度。
分离度可以理解为反映一个样本点与类外元素的紧密程度。

为什么?

为什么轮廓系数可以评价聚类效果的好坏?怎样评价效果好坏?

轮廓系数的公式如下:
S ( i ) = b ( i ) a ( i ) m a x { a ( i ) , b ( i ) } S(i) = \frac{b(i)-a(i)}{max\{a(i), b(i)\}}

其中, a ( i ) a(i) 代表样本点的内聚度,计算方式如下:
a ( i ) = 1 n 1 j i n d i s t a n c e ( i , j ) a(i) = \frac{1}{n-1}\sum_{j\ne i}^{n}distance(i,j)
其中 j j 代表与样本 i i 在同一个类内的其他样本点, d i s t a n c e distance 代表了求 i i j j 的距离。所以 a ( i ) a(i) 越小说明该类越紧密。

b ( i ) b(i) 的计算方式与 a ( i ) a(i) 类似。只不过需要遍历其他类簇得到多个值 { b 1 ( i ) , b 2 ( i ) , b 3 ( i ) , . . . , b m ( i ) } \{b_1(i),b_2(i),b_3(i),...,b_m(i)\} 从中选择最小的值作为最终的结果。

所以原 S ( i ) S(i)
S ( i ) = { 1 a ( i ) b ( i ) a ( i ) < b ( i ) 0 a ( i ) = b ( i ) b ( i ) a ( i ) 1 a ( i ) > b ( i ) S(i)=\left\{\begin{matrix} 1-\frac{a(i)}{b(i)} & a(i)<b(i)\\ 0& a(i)=b(i)\\ \frac{b(i)}{a(i)}-1 & a(i)>b(i) \end{matrix}\right.

由上式可以发现:
当a(i)>b(i)时,即类内的距离小于类间距离,则聚类结果更紧凑。S的值会趋近于1。越趋近于1代表轮廓越明显。

相反,当a(i)<b(i)时,类内的距离大于类内距离,说明聚类的结果很松散。S的值会趋近于-1,越趋近于-1则聚类的效果越差。

由此可得:

轮廓系数S的取值范围为[-1, 1],轮廓系数越大聚类效果越好。

怎么用?

如何计算轮廓系数,已经说明了。但是轮廓系数如何确定K值呢?

我们需要将K值设定为具体的多个数值,范围可以人为规定,如2到10。每个K值下进行聚类,最终计算聚类结果的轮廓系数。最终将轮廓系数绘制关于K的折线图(绘图更直观)。然后将轮廓系数最大的K值作为最终的K值。

不适用

对于簇结构为凸的数据轮廓系数较高,对于簇结构非凸的轮廓系数较低。
因此,轮廓系数不能在不同的算法之间比较优劣,如统一数据下,可能KMeans的结果就比DBSCAN要好。

示例

如下代码是计算KMeans的轮廓系数的code

from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score

# 定义KMeans,以及K值
kmeans = KMeans(n_clusters=n_clusters)	
# 根据数据data进行聚类,结果存放于result_list中
result_list = kmeans.fit_predict(data)
# 将原始的数据data和聚类结果result_list
# 传入对应的函数计算出该结果下的轮廓系数
score = silhouette_score(data, result_list)

猜你喜欢

转载自blog.csdn.net/qq_19672707/article/details/106857918