如何用Python计算轮廓系数(Silhouette Score)

3 阅读4分钟

你想知道的Python计算轮廓系数的方法,核心是借助sklearn.metrics模块中的silhouette_score(整体轮廓系数)和silhouette_samples(样本级轮廓系数)两个函数,下面从基础用法、完整实战、结果解读三个维度讲透,代码可直接复制运行。

一、核心前提:环境与数据准备

1. 安装依赖库

轮廓系数计算依赖scikit-learn(机器学习库)和基础数据处理库,执行以下命令安装:

pip install scikit-learn numpy pandas matplotlib

2. 数据要求

  • 输入数据需为标准化后的数值型数组(避免量纲影响距离计算);
  • 需先完成聚类(如K-Means),得到每个样本的聚类标签。

二、基础用法:3步计算轮廓系数

步骤1:导入核心函数

# 导入轮廓系数计算函数
from sklearn.metrics import silhouette_score  # 整体轮廓系数(所有样本均值)
from sklearn.metrics import silhouette_samples  # 单个样本的轮廓系数
# 辅助库:聚类算法+数据处理+可视化
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd

步骤2:准备数据与完成聚类

以“用户消费行为数据”为例,先预处理数据并完成K-Means聚类:

# 1. 构造模拟数据(电商用户:月消费金额、月消费频次)
data = {
    '月消费金额(元)': [100, 150, 800, 900, 300, 400, 1500, 1800, 200, 350],
    '月消费频次(次)': [2, 1, 10, 12, 5, 4, 14, 15, 3, 6]
}
df = pd.DataFrame(data)

# 2. 数据标准化(必做!避免量纲影响)
scaler = StandardScaler()
features_scaled = scaler.fit_transform(df[['月消费金额(元)', '月消费频次(次)']])

# 3. 执行K-Means聚类(假设分成3类)
kmeans = KMeans(n_clusters=3, random_state=42, n_init=10)
cluster_labels = kmeans.fit_predict(features_scaled)  # 每个样本的聚类标签

步骤3:计算轮廓系数

# 方法1:计算整体轮廓系数(最常用)
overall_score = silhouette_score(features_scaled, cluster_labels)
print(f"整体轮廓系数:{overall_score:.4f}")  # 输出示例:0.7985

# 方法2:计算每个样本的轮廓系数
sample_scores = silhouette_samples(features_scaled, cluster_labels)
print("\n每个样本的轮廓系数:")
for i, score in enumerate(sample_scores):
    print(f"样本{i+1}{score:.4f}")

输出结果示例

整体轮廓系数:0.7985

每个样本的轮廓系数:
样本1:0.8214
样本2:0.7895
样本3:0.8567
样本4:0.8721
样本5:0.7542
样本6:0.7689
样本7:0.8890
样本8:0.8912
样本9:0.7321
样本10:0.7456

三、进阶实战:对比不同K值的轮廓系数(选最优K)

实际应用中,轮廓系数最核心的用途是确定聚类的最优K值,完整代码如下:

# 1. 定义K值范围(比如2到6)
k_range = range(2, 7)
silhouette_scores = []

# 2. 遍历不同K值,计算轮廓系数
for k in k_range:
    kmeans = KMeans(n_clusters=k, random_state=42, n_init=10)
    labels = kmeans.fit_predict(features_scaled)
    # 计算当前K值的整体轮廓系数
    score = silhouette_score(features_scaled, labels)
    silhouette_scores.append(score)
    print(f"K={k} 时,轮廓系数:{score:.4f}")

# 3. 可视化轮廓系数变化,选最优K
plt.figure(figsize=(8, 5))
plt.plot(k_range, silhouette_scores, marker='o', color='blue', linestyle='-')
plt.title('不同K值的轮廓系数对比(选最优K)')
plt.xlabel('聚类数K')
plt.ylabel('轮廓系数')
plt.grid(alpha=0.3)
# 标记最优K值(轮廓系数最大的点)
best_k = k_range[np.argmax(silhouette_scores)]
plt.axvline(x=best_k, color='red', linestyle='--', label=f'最优K={best_k}')
plt.legend()
plt.show()

结果解读

K=2 时,轮廓系数:0.6852
K=3 时,轮廓系数:0.7985  # 最大值,最优K
K=4 时,轮廓系数:0.7012
K=5 时,轮廓系数:0.6123
K=6 时,轮廓系数:0.5541
  • K=3时轮廓系数最高,说明将数据分为3类时聚类效果最好;
  • K>3后轮廓系数持续下降,说明“过度聚类”(拆分的类别无实际意义)。

四、关键注意事项(避坑必看)

  1. 必须标准化数据:轮廓系数基于欧氏距离计算,若特征量纲差异大(如“金额(元)”和“频次(次)”),会导致结果失真,务必先用StandardScaler/MinMaxScaler标准化;
  2. 高维数据先降维:若数据是100+维的高维数据,先通过PCA降维到2-5维,再计算轮廓系数(高维数据的距离计算无意义);
  3. 异常值需提前清洗:极端异常值会拉高样本间的距离,导致轮廓系数偏低,建议用四分位数法剔除离群点;
  4. 样本数不宜过多silhouette_score计算复杂度较高,样本数超过10万时,建议用Mini-Batch K-Means聚类后再抽样计算;
  5. 不替代业务逻辑:轮廓系数高仅代表“聚类效果好”,最终K值需结合业务场景(比如用户分群业务中,即使K=4的轮廓系数略低,但业务上4类更合理,仍选K=4)。