【Python机器学习】聚类算法的对比与评估——用真实值评估聚类

发布于:2024-07-01 ⋅ 阅读:(14) ⋅ 点赞:(0)

在应用聚类算法时,挑战之一就是很难评估一个算法的效果好坏,也很难比较不同算法的结果。

有一些指标可用于评估聚类算法相对于真实聚类的结果,其中最重要的是调整rand指数(ARI)和归一化互信息(NMI),二者都给出了定量的度量,最佳值是1,0表示不相关的聚类。

下面,用ARI比较k均值、凝聚聚类、DBSCAN算法:


import matplotlib.pyplot as plt
import mglearn
import numpy as np
from sklearn.metrics.cluster import adjusted_rand_score
from sklearn.datasets import make_moons,make_blobs
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans
from sklearn.decomposition import NMF,PCA
from sklearn.cluster import AgglomerativeClustering
from sklearn.cluster import DBSCAN

plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

X,y=make_moons(n_samples=200,noise=0.05,random_state=0)

#将数据缩放成平均值为0、方差为1
scaler=StandardScaler()
scaler.fit(X)
X_scaler=scaler.transform(X)

fig,axes=plt.subplots(1,4,figsize=(15,3),subplot_kw={'xticks':(),'yticks':()})

#列出要用的算法
algorithms=[KMeans(n_clusters=2),AgglomerativeClustering(n_clusters=2),DBSCAN()]

#创建一个随机的簇分配,作为参考
random_state=np.random.RandomState(seed=0)
random_clusters=random_state.randint(low=0,high=2,size=len(X))

axes[0].scatter(X_scaler[:,0],X_scaler[:,1],c=random_clusters,cmap=mglearn.cm3,s=60)
axes[0].set_title('随机分配-ARI:{:.2f}'.format(adjusted_rand_score(y,random_clusters)))

for ax,algorithm in zip(axes[1:],algorithms):
    clusters=algorithm.fit_predict(X_scaler)
    ax.scatter(X_scaler[:,0],X_scaler[:,1],c=clusters,cmap=mglearn.cm3,s=60)
    ax.set_title('{}-ARI:{:.2f}'.format(algorithm.__class__.__name__,adjusted_rand_score(y,clusters)))

plt.show()

可以看到,调整rand指数给出了符合直觉的结果,随机簇分配的分数为0,而DBSCAN的分数为1,完美的找到了期望中的聚类。

用这种方式评估时,一个常见的错误是使用了accuracy_score而不是adjusted_rand_score、normalized_info_score或其他聚类指标。使用精度的问题在于,它要求分配的簇标签与真实值完全匹配。但簇标签本身毫无意义——唯一重要的是哪些点位于同一个簇中。

from sklearn.metrics.cluster import adjusted_rand_score
from sklearn.metrics import accuracy_score


cluters1=[0,0,1,1,0]
cluters2=[1,1,0,0,1]

print('Accuracy:{:.2f}'.format(accuracy_score(cluters1,cluters2)))
print('ARI:{:.2f}'.format(adjusted_rand_score(cluters1,cluters2)))