You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

高维不可视数据下Kmeans聚类算法性能评估及标签匹配疑问

嘿,针对你遇到的KMeans高维数据评估和真实标签匹配的问题,我整理了实用的解决方案:

一、高维数据下KMeans的性能评估方法

因为数据维度太高没法可视化,咱们可以从**内部指标(无需真实标签)外部指标(有真实标签时)**两方面来评估:

  • 内部指标(无真实标签可用)

    • 肘部法则:计算不同k值下的inertia_(簇内样本到簇中心的平方和总和),当k增加到某个值后,inertia的下降速度会突然变缓,这个点就是比较合适的聚类数。在sklearn里你可以这么做:遍历不同的k,调用KMeans(n_clusters=k).fit(X).inertia_来收集数值,然后画折线图找拐点。
    • 轮廓系数:衡量每个样本与自身簇内样本的相似度,以及和其他簇样本的差异,取值范围是[-1,1],越接近1说明聚类效果越好。用sklearn的sklearn.metrics.silhouette_score(X, labels)就能计算,不过高维数据计算起来可能有点耗时,如果样本量大的话可以抽部分样本计算。
    • Calinski-Harabasz指数:计算簇间离散度和簇内离散度的比值,数值越大说明簇之间越分开、簇内越紧凑,聚类效果越好。对应方法是sklearn.metrics.calinski_harabasz_score(X, labels)
  • 外部指标(有真实标签时):这部分其实和你第二个问题相关,咱们下面专门讲标签匹配后怎么验证。

二、解决KMeans簇标签与真实标签不匹配的验证问题

这里要重点说一下:KMeans的簇标签是随机分配的,比如你的真实标签是[0,1,2],KMeans可能输出[2,0,1],编号完全不对应,但聚类的分组可能是对的。所以不能直接用普通的准确率来评估,得用这些不依赖标签顺序的方法:

  • 调整兰德指数(ARI):专门用来衡量聚类结果和真实标签的相似度,它会排除随机聚类带来的巧合,取值范围是[-1,1],1表示聚类结果和真实标签完全一致。调用sklearn.metrics.adjusted_rand_score(true_labels, pred_labels)就能得到结果。
  • 归一化互信息(NMI):基于信息论的指标,衡量两个标签分布之间的互信息,归一化后取值在[0,1]之间,值越接近1说明聚类结果和真实标签的匹配度越高。对应方法是sklearn.metrics.normalized_mutual_info_score(true_labels, pred_labels)
  • 匹配标签后计算准确率(直观展示):如果你想得到类似准确率的直观数值,可以先用匈牙利算法找到KMeans簇标签和真实标签的最优映射,然后替换簇标签再计算准确率。举个简单的代码例子:
    import numpy as np
    from scipy.optimize import linear_sum_assignment
    from sklearn.metrics import accuracy_score
    from sklearn.cluster import KMeans
    
    # 假设X是你的特征数据,true_labels是真实标签,n_clusters是聚类数
    kmeans = KMeans(n_clusters=n_clusters, random_state=42)
    pred_labels = kmeans.fit_predict(X)
    
    # 构建代价矩阵,用两个标签的共现次数的负值(因为linear_sum_assignment找最小代价)
    cost_matrix = -np.array([[np.sum((true_labels == i) & (pred_labels == j)) 
                              for j in range(n_clusters)] 
                             for i in range(n_clusters)])
    # 找到最优匹配
    row_ind, col_ind = linear_sum_assignment(cost_matrix)
    # 建立簇标签到真实标签的映射
    label_map = {col_ind[i]: row_ind[i] for i in range(n_clusters)}
    # 替换KMeans的标签
    mapped_pred_labels = np.array([label_map[label] for label in pred_labels])
    # 计算准确率
    acc = accuracy_score(true_labels, mapped_pred_labels)
    print(f"匹配后的准确率: {acc:.4f}")
    

内容的提问来源于stack exchange,提问作者Ali Raza

火山引擎 最新活动