Python中K-Means多轮迭代的簇标签标准化方法问询
嘿,这个问题太典型了——k-means的簇标签本身就是随机分配的,完全不具备语义一致性,所以我们要做的核心就是把不同迭代的簇标签映射到同一个基准体系,这样就能轻松做多数投票了。我给你一套Python的实操方案,用pandas和scipy就能搞定:
核心逻辑
每次k-means运行的簇编号是随机的,但簇对应的样本集合是稳定的(除了少数边界样本)。我们需要:
- 选一个基准簇标签集(比如第一次迭代的结果)
- 对其他每一次迭代的标签,计算它和基准集的最优映射关系(用匈牙利算法找最大重叠的簇对应)
- 把所有迭代的标签都转换成基准体系的标签,最后替换成你想要的a/b/c格式
代码实现
首先导入需要的库:
import pandas as pd import numpy as np from scipy.optimize import linear_sum_assignment
然后定义一个用来映射标签的工具函数:
def align_cluster_labels(base_labels, target_labels): # 第一步:构建混淆矩阵,统计基准簇和目标簇的样本重叠数 n_clusters = len(np.unique(base_labels)) confusion_matrix = np.zeros((n_clusters, n_clusters), dtype=int) for base_label, target_label in zip(base_labels, target_labels): confusion_matrix[base_label, target_label] += 1 # 第二步:用匈牙利算法找到最优映射(最大化簇之间的重叠样本数) # 因为linear_sum_assignment是找最小值,所以我们传入负的混淆矩阵 row_indices, col_indices = linear_sum_assignment(-confusion_matrix) # 构建目标标签到基准标签的映射字典 label_mapping = {target: base for base, target in zip(row_indices, col_indices)} # 第三步:将目标标签映射为基准标签 aligned_labels = target_labels.map(label_mapping) return aligned_labels
接下来处理你的DataFrame:
# 假设你的原始数据框叫cluster_results,先把sample_name设为索引(方便操作) cluster_results = cluster_results.set_index('sample_name') # 选择第一次迭代的结果作为基准标签 base_labels = cluster_results['iter1'] # 遍历所有其他迭代列,对齐标签 for col in cluster_results.columns[1:]: cluster_results[col] = align_cluster_labels(base_labels, cluster_results[col]) # 将数字标签替换为你想要的a/b/c格式 cluster_results = cluster_results.replace({0: 'a', 1: 'b', 2: 'c'}) # 最后计算每个样本的多数投票(取每行出现次数最多的标签) cluster_results['final_cluster'] = cluster_results.mode(axis=1)[0]
关键细节解释
- 混淆矩阵:它的作用是统计“基准簇X和目标簇Y有多少共同样本”,数值越大说明这两个簇其实是同一个簇(只是编号不同)。
- 匈牙利算法:这是解决指派问题的经典算法,能帮我们找到一组簇的对应关系,让总重叠样本数最大化,保证标签映射的合理性。
- 多数投票:用
mode(axis=1)可以直接获取每行出现次数最多的标签,对于像x3这种边界样本,会自动给出它最常归属的簇。
额外小贴士
- 如果你的聚类不是100%稳定,这个方法依然有效——它是基于整体簇的重叠来映射,不会被个别不稳定样本干扰。
- 如果你不想用第一次迭代作为基准,也可以先计算所有迭代的簇中心,再把每个迭代的簇中心和平均中心做匹配,结果是一样的,只是步骤稍复杂一点。
内容的提问来源于stack exchange,提问作者AndreyIto
相关产品推荐
相关产品推荐

