轮廓系数是衡量聚类质量的内部评估指标,通过计算每个样本的内聚度a(i)与分离度b(i),代入公式s(i)=(b(i)−a(i))/max(a(i),b(i))得到[-1,1]范围内的值,再取均值得到整体轮廓系数;它必须同时依赖原始特征数据x和簇标签labels,因为距离计算需在聚类所处的实际特征空间中进行,仅用labels无法还原样本间距离关系。

轮廓系数是什么,为什么不能直接用 labels 算
轮廓系数(Silhouette Score)衡量的是每个样本与其所属簇的内聚性(cohesion)和与其他簇的分离性(separation)的平衡。它不是对聚类结果的“整体打分”,而是对每个样本计算一个 [-1, 1] 区间的值,再取均值。所以你必须同时提供原始数据 X 和对应的簇标签 labels,缺一不可——只给 labels 或只给距离矩阵是无效的。
常见错误是误以为轮廓系数能评估任意标签划分的好坏,比如拿 KMeans 的结果直接喂给某个“轮廓函数”却不传原始特征;或者在降维后(如 PCA)用了新坐标却忘了同步更新 X,导致分数失真。
用 sklearn.metrics.silhouette_score 计算时的关键参数
核心函数是 silhouette_score,不是 silhouette_samples(后者返回每个点的值,前者返回平均值)。它默认使用欧氏距离,但实际行为受以下参数影响极大:
-
metric:必须与你聚类时使用的距离一致。KMeans 默认欧氏距离,就别设成'manhattan',否则分数不可比 -
sample_size:大数据集建议设为整数(如10000),否则全量计算极慢;但设了这个参数后结果是随机采样的估计值,两次运行可能略有浮动 -
random_state:仅当sample_size非 None 时生效,用于复现实验 - 注意:该函数会自动忽略标签全相同的极端情况(即所有点被分到一个簇),并抛出
ValueError: Number of labels is 1
怎样避免因预处理不一致导致轮廓系数失真
轮廓系数对特征尺度极度敏感。如果你用 StandardScaler 对数据做了归一化,但评估时用的是原始 X,算出来的分数毫无意义——因为聚类本身是在缩放后的空间里做的,而轮廓系数计算距离时也得在同一个空间。
正确做法是:确保传入 silhouette_score 的 X 和你训练模型时用的 X 完全一致(包括是否缩放、是否降维、是否去噪)。
快速生成专业的 Python 脚本和应用代码。一键创建完整项目结构,支持CLI、API、爬虫、Bot、Django等多种项目类型,包含完整的项目结构、配置文件、依赖管理、测试、README和文档。
示例片段:
from sklearn.preprocessing import StandardScaler from sklearn.cluster import KMeans from sklearn.metrics import silhouette_score <p>scaler = StandardScaler() X_scaled = scaler.fit_transform(X) # 聚类用这个 kmeans = KMeans(n_clusters=3).fit(X_scaled) score = silhouette_score(X<em>scaled, kmeans.labels</em>) # 评估也用这个,不是 X!</p>
轮廓系数低一定说明聚类差吗?要看数据分布
轮廓系数接近 0.7 是不错,0.5 可接受,低于 0.25 往往意味着簇结构模糊。但它不是万能指标:对于环形、月牙形或密度差异极大的簇(比如 DBSCAN 擅长的场景),欧氏距离下的轮廓系数天然吃亏——因为它的定义依赖“最近邻簇中心”的假设,而这类结构根本没有明确中心。
此时若强行用 silhouette_score,可能得到很低的分,但这不等于算法失败;更合理的做法是结合 silhouette_samples 查看分布,或换用 calinski_harabasz_score、davies_bouldin_score 对比验证。
真正容易被忽略的一点:轮廓系数只反映“当前 n_clusters 下的相对质量”,它不能替代肘部法则或领域知识来决定最优簇数——你得在多个 k 上反复算,再看曲线拐点。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










