一、聚类算法的模型评估指标:轮廓系数
### --- 聚类算法的模型评估指标:轮廓系数
~~~ 不同于分类模型和回归,聚类算法的模型评估不是一件简单的事。
~~~ 在分类中,有直接结果(标签)的输出,并且分类的结果有正误之分,
~~~ 所以我们使用预测的准确度,混淆矩阵,ROC 曲线等等指标来进行评估,
~~~ 但无论如何评估,都是在”模型找到正确答案“的能力。
~~~ 而回归中,由于要拟合数据,我们有 SSE均方误差,有损失函数来衡量模型的拟合程度。
~~~ 但这些衡量指标都不能够使用于聚类。
~~~ 面试高危问题:如何衡量聚类算法的效果?
~~~ 聚类模型的结果不是某种标签输出,并且聚类的结果是不确定的,
~~~ 其优劣由业务需求或者算法需求来决定,并且没有永远的正确答案。那我们如何衡量聚类的效果呢?
~~~ 记得我们说过,KMeans 的目标是确保“簇内差异小,簇外差异大”,
~~~ 我们就可以通过衡量簇内差异来衡量聚类的效果。
~~~ 我们刚才说过,Inertia 是用距离来衡量簇内差异的指标,
~~~ 因此,我们是否可以使用Inertia 来作为聚类的衡量指标呢?Inertia 越小模型越好。
~~~ 可以,但是这个指标的缺点和极限太大。
~~~ 它不是有界的。我们只知道,Inertia 是越小越好,是 0 最好,但我们不知道,
~~~ 一个较小的Inertia究竟有没有达到模型的极限,能否继续提高。
~~~ 它的计算太容易受到特征数目的影响,数据维度很大的时候,
~~~ Inertia 的计算量会陷入维度诅咒之中,计算量会爆炸,不适合用来一次次评估模型。
~~~ 它会受到超参数 K 的影响,在我们之前的尝试中其实我们已经发现,
~~~ 随着 K 越大,Inertia 注定会越来越小,但这并不代表模型的效果越来越好了。
~~~ Inertia 作为评估指标,会让聚类算法在一些细长簇,环形簇,
~~~ 或者不规则形状的流形时表现不佳:
![](https://i-blog.csdnimg.cn/blog_migrate/ebb9fcbdaedc74160f437eb60e7266cd.png)
~~~ # 那我们可以使用什么指标呢?聚类是没有标签,即不知道真实答案的预测算法,
~~~ # 我们必须完全依赖评价簇内的稠密程度(簇内差异小)和簇间的离散程度(簇外差异大)来评估聚类的效果。
~~~ # 其中轮廓系数是最常用的聚类算法的评价指标。它是对每个样本来定义的,它能够同时衡量:
~~~ 样本与其自身所在的簇中的其他样本的相似度 a,等于样本与同一簇中所有其他点之间的平均距离
~~~ 样本与其他簇中的样本的相似度 b,等于样本与下一个最近的簇中的所有点之间的平均距离
~~~ 根据聚类的要求”簇内差异小,簇外差异大“,我们希望 b 永远大于 a,并且大得越多越好。
~~~ 单个样本的轮廓系数计算为:
![](https://i-blog.csdnimg.cn/blog_migrate/f7e276a3db400671464ec694dc197ebc.png)
~~~ # 很容易理解轮廓系数范围是(-1,1):
~~~ 轮廓系数越接近 1:样本与自己所在的簇中的样本很相似,并且与其他簇中的样本不相似。
~~~ 轮廓系数为 0 时:两个簇中的样本相似度一致,两个簇本应该是一个簇。
~~~ 轮廓系数为负时:样本点与簇外的样本更相似。
~~~ 如果一个簇中的大多数样本具有比较高的轮廓系数,则簇会有较高的总轮廓系数,
~~~ 则整个数据集的平均轮廓系数越高,则聚类是合适的。
~~~ 如果许多样本点具有低轮廓系数甚至负值,则聚类是不合适的,
~~~ 聚类的超参数 K 可能设定得太大或者太小。
~~~ 在 sklearn 中,我们使用模块 metrics 中的类 silhouette_score 来计算轮廓系数,
~~~ 它返回的是一个数据集中,所有样本的轮廓系数的均值。
~~~ 但我们还有同在 metrics 模块中的 silhouette_sample,它的参数与轮廓系数一致,
~~~ 但返回的是数据集中每个样本自己的轮廓系数。
~~~ 我们来看看轮廓系数在我们自建的数据集上表现如何:
from sklearn.metrics import silhouette_score
from sklearn.metrics import silhouette_samples
X
y_pred
array([[-6.92324165e+00, -1.06695320e+01],
[-8.63062033e+00, -7.13940564e+00],
[-9.63048069e+00, -2.72044935e+00],
[-2.30647659e+00…]])
array([0, 0, 2, 1, 2, 1, 2, 2, 2, 2, 0, 0, 2, 1, 2, 0, 2, 0, 1, 2, 2, 2,
2, 1, 2, 2, 1, 1, 2, 2…])
~~~ # 观察一下不同的 K 下,轮廓系数发生什么变化?
~~~ # 观察一下不同的K下,轮廓系数发生什么变化?
cluster = KMeans(n_clusters=3, random_state=0).fit(X)
silhouette_score(X,cluster_.labels_) #计算所有样本的轮廓系数均值。
silhouette_samples(X,cluster.labels_) #计算每个样本的轮廓系数。
array([ 3.32141517e-01, 5.02867308e-01, 5.69286243e-01, 8.26239736e-01,
3.52953508e-01, 7.40603896e-01, 6.92621728e-01, 5.90288043e-01,
4.17153302e-02, 7.35814660e-01…])
import pandas as pd
score=[]
for i in range(2,100):
cluster= KMeans(n_clusters=i, random_state=0).fit(X)
score.append(silhouette_score(X,cluster.labels_))
plt.plot(range(2,100),score)
plt.axvline(pd.DataFrame(score).idxmin()[0]+2,ls=':')
![](https://i-blog.csdnimg.cn/blog_migrate/78b7377c1e9f819b31a620ce3d8464fb.png)
~~~ 轮廓系数有很多优点,它在有限空间中取值,使得我们对模型的聚类效果有一个“参考”。
~~~ 并且,轮廓系数对数据的分布没有假设,因此在很多数据集上都表现良好。
~~~ 但它在每个簇的分割比较清洗时表现最好。
~~~ 但轮廓系数也有缺陷,比如基于密度进行的聚类,
~~~ 或通过 DBSCAN 获得的聚类结果,如果使用轮廓系数来衡量,则会表现出比真实聚类效果更高的分数。