K-means聚类负轮廓系数原因排查及分数提升方法
代码存在的明确错误
你的代码有1个直接导致轮廓系数为负的核心bug,1个笔误:
- 核心bug:轮廓系数计算传入的数据集错误。你是在标准化后的
Xnorm上训练的KMeans模型,距离计算完全基于标准化后的特征尺度,但计算轮廓系数时传入的是未做任何缩放的原始数据集X,两者尺度完全不匹配,计算出的欧氏距离和模型训练时用的距离没有一致性,输出负的轮廓系数是必然结果。 - 笔误:代码注释标注k=3,但实际传入的聚类数参数
n_clusters=4,该问题不会直接导致指标错误,但容易引发后续结果解读偏差。
移除StandardScaler后轮廓系数升至0.6的原因
这个0.6是虚假的高值,不代表聚类效果变好,核心原因是KMeans完全基于欧氏距离计算样本相似度,对特征尺度极度敏感:
你对分类变量做哑变量编码后,所有哑变量的取值都是0/1,而原始连续变量的取值范围往往远大于[0,1](比如客户消费额、账户余额这类变量可能从0到几万甚至几十万)。去掉标准化步骤后,大尺度连续变量的距离贡献会完全碾压哑变量:举个例子,两个样本在消费额上差1000元,带来的欧氏距离平方贡献是1000000,而两个样本在某个哑变量上取值不同,带来的距离平方贡献仅为1,相当于所有哑变量携带的分类信息在距离计算中权重几乎为0,模型本质是只用了少数几个大尺度连续变量做聚类。这种情况下簇内样本在这几个连续变量上的相似度天然很高,算出来的轮廓系数自然高,但你前期做的分类变量编码、希望纳入分类维度信息做客户分群的目标完全没有实现。
而你之前在标准化后得到负轮廓系数,除了前面提到的轮廓系数计算传错数据集的bug,还有一个原因:Z-score标准化会把0/1取值的哑变量转换为带正负值的缩放结果,如果你数据集中哑变量的数量远多于连续变量,标准化后哑变量的权重会被不合理拉高,挤压连续变量的贡献,再叠加评估数据集用错的问题,最终得到了负的指标值。
提升KMeans聚类轮廓系数的可落地方法
- 先修复基础代码问题:轮廓系数计算必须传入和模型训练完全一致的数据集,如果用标准化后的数据训练,就要将
Xnorm传入silhouette_score;统一代码注释和参数中的聚类数值,避免笔误。 - 调整特征缩放逻辑:不要对包含哑变量的数据集直接全量做Z-score标准化。更合理的方式是对连续变量做
MinMaxScaler缩放至[0,1]区间,和哑变量的取值范围对齐,保证所有特征在距离计算中的初始权重一致,不会出现某类特征完全主导距离计算的问题。 - 选择最优聚类数k:不要直接拍脑袋定k=4,可以遍历k从2到10的取值,分别计算每个k对应的轮廓系数、SSE值,选轮廓系数最高、SSE下降出现明显拐点的k值,不合适的k值会直接导致簇间区分度差、轮廓系数低。
- 清理噪声特征:提前删除方差极低的哑变量——如果某个分类水平的样本占比低于1%,对应的哑变量99%取值都是0,这类特征对聚类几乎没有有效贡献,反而会引入距离计算噪声。
- 调整KMeans训练参数:你当前设置的
max_iter=30偏小,很可能模型还没收敛就停止迭代;n_init=10也容易让模型落到局部最优解,可以将n_init调整到20以上,max_iter调整到300,保证模型能收敛到更优的分群结果。 - 适配数据类型选算法:如果你的数据集中哑变量(分类特征)占比很高,不要硬用KMeans——KMeans本身是为连续型、球形分布数据设计的算法,哑变量过多时效果会很差,可以换成K-Prototypes算法,该算法专门针对混合分类、连续变量的数据集设计,不需要给分类变量做哑变量编码,可以直接处理分类特征,分群合理性会明显提升。
内容的提问来源于stack exchange,提问作者Fábio Pires
相关产品推荐
相关产品推荐

