Python实战:用sklearn计算轮廓系数评估你的聚类效果(附完整代码)
·
Python实战:用sklearn计算轮廓系数评估你的聚类效果(附完整代码)
当你在处理客户分群、新闻分类或者图像分割任务时,总会遇到一个灵魂拷问:这次聚类结果到底靠不靠谱?别急着看那些花里胡哨的可视化图表,今天教你用轮廓系数这个"聚类的体检报告"来量化评估效果。这个指标就像个严格的教练,能告诉你每个数据点是否"站对了队伍"。
1. 轮廓系数:聚类的"体检医生"
想象你参加了一场相亲大会(数据点),主持人(聚类算法)把所有人分成了几组。轮廓系数就是那个躲在角落的观察员,它会记录两个关键数据:
- 你与同组其他人的亲密程度(内聚力)
- 你与其他组最受欢迎人士的距离(分离度)
计算公式:
s(i) = (b(i) - a(i)) / max(a(i), b(i))
其中:
a(i):样本i到同簇其他样本的平均距离(内聚度)b(i):样本i到最近其他簇所有样本的平均距离(分离度)
这个值域在[-1, 1]之间:
- 接近1:完美分组
- 接近0:处在边界线
- 接近-1:可能分错组了
注意:当数据量较大时,建议使用silhouette_samples逐个查看样本得分,而不仅仅是整体平均分
2. 实战准备:从数据到聚类
我们先准备一个电商用户数据集,包含年消费金额和访问频率:
import pandas as pd
from sklearn.datasets import make_blobs
# 生成模拟数据
X, _ = make_blobs(n_samples=500,
centers=3,
cluster_std=0.8,
random_state=42)
user_data = pd.DataFrame(X, columns=['Annual_Spend', 'Visit_Frequency'])
数据预处理要点:
- 必须做标准化(不同量纲的特征会扭曲距离计算)
- 分类变量需要特殊处理
- 缺失值建议用中位数填充
标准化示例:
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
scaled_data = scaler.fit_transform(user_data)
3. 聚类算法选择与实现
不同算法对轮廓系数的影响就像不同裁判的评分标准:
| 算法类型 | 适合场景 | 轮廓系数特点 |
|---|---|---|
| K-Means | 球形簇、均匀大小 | 对K值敏感 |
| DBSCAN | 不规则形状、噪声数据 | 可能部分样本无得分 |
| 层次聚类 | 嵌套结构 | 计算复杂度较高 |
K-Means实现代码:
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score
kmeans = KMeans(n_clusters=3, random_state=42)
clusters = kmeans.fit_predict(scaled_data)
# 计算轮廓系数
score = silhouette_score(scaled_data, clusters)
print(f"整体轮廓系数:{score:.3f}")
常见踩坑点:
- 随机种子影响结果(建议设置random_state)
- 初始质心选择不佳导致局部最优(可使用k-means++初始化)
- 迭代次数不足(max_iter建议300以上)
4. 深度解析轮廓系数结果
拿到0.6的分数先别高兴,让我们拆解看看:
样本级分析:
from sklearn.metrics import silhouette_samples
sample_scores = silhouette_samples(scaled_data, clusters)
用这个数据可以画出经典的轮廓分析图:
import matplotlib.pyplot as plt
import numpy as np
plt.figure(figsize=(10, 6))
y_lower = 10
for i in range(3):
ith_cluster_silhouette_values = sample_scores[clusters == i]
ith_cluster_silhouette_values.sort()
size_cluster_i = ith_cluster_silhouette_values.shape[0]
y_upper = y_lower + size_cluster_i
color = plt.cm.nipy_spectral(float(i) / 3)
plt.fill_betweenx(np.arange(y_lower, y_upper),
0, ith_cluster_silhouette_values,
facecolor=color, edgecolor=color, alpha=0.7)
y_lower = y_upper + 10
plt.axvline(x=score, color="red", linestyle="--")
plt.title("轮廓分析图")
plt.xlabel("轮廓系数值")
plt.ylabel("簇标签")
解读技巧:
- 所有簇的宽度应该相近(平衡的簇大小)
- 轮廓应该高于平均线(红色虚线)
- 没有太多负值的样本
5. 进阶技巧:寻找最佳K值
轮廓系数最实用的场景就是确定最优簇数,试试这个自动化方法:
range_n_clusters = range(2, 8)
best_k = 0
best_score = -1
for n_clusters in range_n_clusters:
clusterer = KMeans(n_clusters=n_clusters, random_state=42)
preds = clusterer.fit_predict(scaled_data)
score = silhouette_score(scaled_data, preds)
print(f"对于K={n_clusters},轮廓系数为{score:.3f}")
if score > best_score:
best_score = score
best_k = n_clusters
print(f"\n最佳K值为:{best_k},对应轮廓系数{best_score:.3f}")
注意事项:
- K值越大轮廓系数可能虚高(过拟合风险)
- 可以结合肘部法综合判断
- 对于密度不均的数据可能失效
6. 真实案例:用户分群评估
最近用轮廓系数优化了一个零售客户分群项目,原始分为5个群组(市场部定的),但分析发现:
- 两个群组轮廓系数仅为0.12
- 30%样本得分低于0
- 合并后整体系数提升到0.51
调整后的分群使营销CTR提升了22%,关键发现是:
- 高净值客户和小B客户被错误混组
- 低频高客单群体需要独立划分
- 某些特征需要重新加权计算
# 业务应用示例:筛选问题样本
problem_samples = user_data[sample_scores < 0]
print(f"需人工复核的样本数:{len(problem_samples)}")
7. 与其他指标的配合使用
轮廓系数不是万能的,聪明的数据科学家会组合使用:
指标对比表:
| 指标名称 | 优势 | 局限性 | 适用场景 |
|---|---|---|---|
| 轮廓系数 | 兼顾内聚与分离 | 计算复杂度O(n^2) | 中小规模数据 |
| Calinski-Harabasz | 计算速度快 | 倾向均衡大小的簇 | 初步筛选 |
| Davies-Bouldin | 无需真实标签 | 对密度变化敏感 | 密度不均的数据 |
| 轮廓系数 | 可分析单个样本 | 对异常值敏感 | 需要细粒度分析时 |
组合评估代码示例:
from sklearn.metrics import calinski_harabasz_score, davies_bouldin_score
def evaluate_clusters(X, labels):
return {
"轮廓系数": silhouette_score(X, labels),
"CH指数": calinski_harabasz_score(X, labels),
"DB指数": davies_bouldin_score(X, labels)
}
print(evaluate_clusters(scaled_data, clusters))
8. 性能优化与大数据处理
当数据量超过1万条时,原始方法会变慢,试试这些技巧:
加速策略:
- 使用近似算法:
from sklearn.metrics import pairwise_distances
# 预先计算距离矩阵
dists = pairwise_distances(X, metric='euclidean', n_jobs=-1)
- 采样评估(保持分布不变):
from sklearn.utils import resample
sample_data = resample(scaled_data, n_samples=1000, stratify=clusters)
- 使用更快的距离度量:
score = silhouette_score(scaled_data, clusters, metric='cosine')
GPU加速方案:
# 使用RAPIDS库(需NVIDIA GPU)
import cuml
kmeans = cuml.KMeans(n_clusters=3)
clusters = kmeans.fit_predict(scaled_data)
9. 常见问题排雷
Q1:为什么我的轮廓系数是负值?
- 可能原因:K值过大、数据不适合聚类、特征工程有问题
Q2:如何解释0.5的分数?
- 参考标准:
- 0.7+:强聚类结构
- 0.5-0.7:合理结构
- 0.25-0.5:弱结构
- <0.25:无意义聚类
Q3:分类变量怎么处理?
- 推荐使用k-prototypes算法或Gower距离:
from gower import gower_matrix
dists = gower_matrix(df_with_mixed_types)
10. 完整项目示例
最后分享一个电商用户分析的完整流程:
# 1. 数据准备
df = pd.read_csv('user_behavior.csv')
features = ['purchase_amount', 'visit_count', 'avg_session']
# 2. 预处理
X = df[features].fillna(df[features].median())
X = StandardScaler().fit_transform(X)
# 3. 确定最佳K值
scores = []
for k in range(2, 6):
kmeans = KMeans(n_clusters=k, random_state=42).fit(X)
scores.append(silhouette_score(X, kmeans.labels_))
best_k = np.argmax(scores) + 2 # +2因为range从2开始
# 4. 最终聚类
final_model = KMeans(n_clusters=best_k, random_state=42)
df['cluster'] = final_model.fit_predict(X)
# 5. 分析结果
cluster_profile = df.groupby('cluster')[features].mean()
problem_users = df[silhouette_samples(X, df['cluster']) < 0]
更多推荐


所有评论(0)