前言
在机器学习中,无监督学习算法中聚类算法算作相对重要的一部分算法。也常在低资源和无标注的情况下使用。
其中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)\}}
S(i)=max{a(i),b(i)}b(i)−a(i)
其中,
a
(
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)
a(i)=n−11j=i∑ndistance(i,j)
其中
j
j
j代表与样本
i
i
i在同一个类内的其他样本点,
d
i
s
t
a
n
c
e
distance
distance代表了求
i
i
i与
j
j
j的距离。所以
a
(
i
)
a(i)
a(i)越小说明该类越紧密。
b ( i ) b(i) b(i)的计算方式与 a ( 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)\} {b1(i),b2(i),b3(i),...,bm(i)}从中选择最小的值作为最终的结果。
所以原
S
(
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.
S(i)=⎩⎪⎨⎪⎧1−b(i)a(i)0a(i)b(i)−1a(i)<b(i)a(i)=b(i)a(i)>b(i)
由上式可以发现:
当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)