本帖最后由 lospring 于 2024-8-4 19:23 编辑
k-Means是无监督学习的算法之一。k-means就是将n个数据点进行聚类分析,得到 k 个聚类,使得每个数据点到聚类中心的距离最小。
k-Means的相关过程很容易获得,整体的推导过程实在是没什么意义再复制出来,下面就看看评估聚性能的方法:
方法1 - ARI
如果被用来评估的数据本身带有正确的类别信息,则利用Adjusted Rand Index(ARI)对聚类结果进行评估,ARI与分类问题中计算准确性的方法类似,兼顾了类簇无法和分类标记一一对应的问题。
1、RI
为了方便理解ARI,先讨论一下RI,也就是rand index,是ARI的基础方法。
假如有两类,那么针对这两类的的RI评价指标为:
a,b,c,d分别代表的含义为:
- a : 应该在一类,最后聚类到一类的数量,
- b : 不应该在一类,最后聚类结果也没把他们聚类在一起的数量。
- c和d那么就是应该在一起而被分开的和不应该在一起而被迫在一起的。毕竟强扭的瓜不甜,c和d固然是错误的。
所以从R的表达式中可以看出,a和b是对的,这样能够保证R在0到1之间,而且,聚类越准确,指标越接近于1.
这里有一个关键性的问题,就是什么叫数量?怎么去计算?准确的说,是配对的数量。比如说a是应该在一起而真的幸福的在一起了的数量,这显然就应该像人类一样按照小夫妻数量计算,但是我们的样本可不管一夫一妻制,任意选两个就是一个配对,所以,就是 n(n−1)/2这样来计算,也就是组合数,n个当中选两个的选法。同时我们看到,分母其实是所有配对的总和,所以,我们最后可以写成这样:
2、ARI
有了先前RI的感性理解之后,接下来解释一下ARI。
RI有一个缺点,就是惩罚力度不够,换句话说,大家普遍得分比较高,没什么区分度,普遍80分以上。这样的话,往往是评价区分性不是特别好,于是就诞生出了ARI,这个指标相对于RI就很有区分度了。
具体的公式是:
ARI取值范围为[-1,1],值越大越好,反映两种划分的重叠程度,使用该度量指标需要数据本身有类别标记。
关联表(contingency table)的定义:
表中:
公式中:
假设配对矩阵是这样的,共有 n(n−1)/2 个配对方法。在行方向计算出可能取到的配对数,在列方向计算可能取到的配对数,相乘以后,除以总的配对数,这就是a的期望了。
from sklearn.metrics import adjusted_rand_score
ari_train = adjusted_rand_score(y_train, kmeans.labels_)
print("ari_train = %f" % ari_train)
方法2 - 轮廓系数
如果被用来评估的数据没有所属类别,则使用轮廓系数(Silhouette Coefficient)来度量聚类结果的质量,评估聚类的效果。轮廓系数同时兼顾了聚类的凝聚度和分离度,取值范围是[-1,1],轮廓系数越大,表示聚类效果越好。
轮廓系数的具体计算步骤:
import numpy as np
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score
import matplotlib.pyplot as plt
plt.rcParams['figure.figsize']=(10,10)
plt.subplot(3,2,1)
x1=np.array([1,2,3,1,5,6,5,5,6,7,8,9,7,9]) #初始化原始数据
x2=np.array([1,3,2,2,8,6,7,6,7,1,2,1,1,3])
X=np.array(list(zip(x1,x2))).reshape(len(x1),2)
plt.xlim([0,10])
plt.ylim([0,10])
plt.title('Instances')
plt.scatter(x1,x2)
colors=['b','g','r','c','m','y','k','b']
markers=['o','s','D','v','^','p','*','+']
clusters=[2,3,4,5,8]
subplot_counter=1
sc_scores=[]
for t in clusters:
subplot_counter +=1
plt.subplot(3,2,subplot_counter)
kmeans_model=KMeans(n_clusters=t).fit(X) #KMeans建模
for i,l in enumerate(kmeans_model.labels_):
plt.plot(x1[i],x2[i],color=colors[l],marker=markers[l],ls='None')
plt.xlim([0,10])
plt.ylim([0,10])
sc_score=silhouette_score(X,kmeans_model.labels_,metric='euclidean') #计算轮廓系数
sc_scores.append(sc_score)
plt.title('k=%s,silhouette coefficient=%0.03f'%(t,sc_score))
plt.figure()
plt.plot(clusters,sc_scores,'*-') #绘制类簇数量与对应轮廓系数关系
plt.xlabel('Number of Clusters')
plt.ylabel('Silhouette Coefficient Score')
plt.savefig('fig-res-k-means_silhouette_coef.pdf')
plt.show()