Python案例如何用Scikit-learn做卡林斯基指数(Calinski-Harabasz Index)
目录导读
卡林斯基指数核心概念详解
卡林斯基指数(Calinski-Harabasz Index),又称方差比准则(Variance Ratio Criterion),是评估聚类效果最常用的内部指标之一,其核心思想是:簇间离散度越大、簇内离散度越小,聚类效果越好。

计算公式为:
CH = (B / (k-1)) / (W / (n-k))
- B:簇间协方差矩阵的迹(越大越好)
- W:簇内协方差矩阵的迹(越小越好)
- k:聚类数量
- n:样本总数
关键特性:该指数值越高,表示聚类结构越清晰,与轮廓系数不同,CH指数对球形簇有天然偏好,且计算速度较快,适合大规模数据集。
Python环境配置与Scikit-learn安装
基础环境准备
# 推荐使用conda或venv创建隔离环境 pip install scikit-learn pandas numpy matplotlib
核心库导入
from sklearn.datasets import make_blobs from sklearn.cluster import KMeans from sklearn.metrics import calinski_harabasz_score import matplotlib.pyplot as plt import pandas as pd
基于KMeans聚类计算卡林斯基指数
1 生成测试数据
# 创建3个簇的样本数据
X, y_true = make_blobs(n_samples=1000, centers=3,
cluster_std=0.5, random_state=42)
2 计算CH指数完整流程
# 训练KMeans模型
kmeans = KMeans(n_clusters=3, random_state=42)
y_pred = kmeans.fit_predict(X)
# 计算卡林斯基指数
ch_score = calinski_harabasz_score(X, y_pred)
print(f"卡林斯基指数: {ch_score:.2f}") # 输出示例:3718.56
3 多K值对比确定最佳聚类数
scores = []
k_range = range(2, 11)
for k in k_range:
km = KMeans(n_clusters=k, random_state=42)
labels = km.fit_predict(X)
scores.append(calinski_harabasz_score(X, labels))
# 可视化分析
plt.plot(k_range, scores, 'bo-')
plt.xlabel('聚类数(k)')
plt.ylabel('卡林斯基指数')'CH指数趋势图 - 最高点对应最优k值')
plt.grid(True)
plt.show()
规律观察:当k=3时CH指数最高,与实际生成数据的3个簇完美吻合。
实战案例:电商客户分群评估
1 数据加载与预处理
# 模拟电商客户数据(年消费金额,平均订单金额,访问频次)
data = pd.DataFrame({
'annual_spend': [12000, 8000, 15000, 4500, ...], # 模拟1000条数据
'avg_order': [250, 180, 320, 120, ...],
'visit_freq': [45, 30, 60, 15, ...]
})
# 标准化处理(重要!CH指数对尺度敏感)
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_scaled = scaler.fit_transform(data)
2 自动化选择最优K值
ch_scores = []
for k in range(2, 11):
km = KMeans(n_clusters=k, random_state=42, n_init=10)
labels = km.fit_predict(X_scaled)
ch_scores.append(calinski_harabasz_score(X_scaled, labels))
optimal_k = range(2, 11)[ch_scores.index(max(ch_scores))]
print(f"最优客户分群数: {optimal_k},对应CH指数: {max(ch_scores):.2f}")
3 最终模型输出
final_model = KMeans(n_clusters=optimal_k, random_state=42)
data['cluster'] = final_model.fit_predict(X_scaled)
# 各群体画像
cluster_profile = data.groupby('cluster').mean()
print(cluster_profile)
输出解读:某电商案例显示k=4时CH指数最高,说明客户应分为4类:高消费高频次VIP、中等消费稳定型、价格敏感低消费型、沉睡流失型。
常见问题与优化问答
Q1:卡林斯基指数取值范围是多少?如何解读?
A:严格来说CH指数没有理论上限。一般准则:
- 对比不同k值下的CH,峰值对应的k为最优
- 数值越大越好,但需结合业务场景,例如某数据集CH=5000可能比CH=3000聚类更清晰,但若CH=10000时k值过大(如k=15),可能过拟合。
Q2:为什么我的CH指数出现负值?
A:理论上是不会出现负值的(方差非负),出现负值通常因为:
- 数据未标准化(尤其属性量纲差异极大)
- 使用了错误的距离度量(如KMeans默认欧氏距离与余弦距离混用)
解决方案:使用StandardScaler或MinMaxScaler预处理数据。
Q3:CH指数与轮廓系数、戴维森-布尔丁指数如何选择?
A: | 指标 | 适用场景 | 计算复杂度 | 对形状敏感度 | |------|----------|------------|--------------| | CH指数 | 球形簇,大数据集 | O(n) | 高 | | 轮廓系数 | 任意形状簇 | O(n²) | 低 | | 戴维森-布尔丁指数 | 需要最小化时 | O(n) | 中 |
建议:用CH指数作为主要参考,配合轮廓系数交叉验证,例如本例中使用CH指数找到k=4最优,再用轮廓系数验证是否同样为4。
Q4:能否用于非KMeans聚类(如DBSCAN、层次聚类)?
A:完全可以!calinski_harabasz_score(X, labels)要求输入两个数组:原始特征X和聚类标签labels。
from sklearn.cluster import AgglomerativeClustering hclust = AgglomerativeClustering(n_clusters=4) labels_hc = hclust.fit_predict(X_scaled) print(calinski_harabasz_score(X_scaled, labels_hc))
注意:但DBSCAN会产生噪声点(标签-1),CH指数无法处理噪声点,需先过滤。
Q5:大数据集下CH指数计算过慢怎么办?
A:
- 降维处理:使用PCA或t-SNE减少特征维度
- 采样计算:从原始数据中随机抽取子集计算,但需保证子集分布与整体一致
- 改用近似算法:如MiniBatchKMeans + CH指数(但结果会浮动)
from sklearn.cluster import MiniBatchKMeans mbk = MiniBatchKMeans(n_clusters=4, batch_size=100) labels_mb = mbk.fit_predict(X_scaled) ch_fast = calinski_harabasz_score(X_scaled, labels_mb)
总结建议
- 标准化是前提:所有基于距离的聚类(KMeans、层次聚类)务必先标准化。
- 组合使用:CH指数 + 肘部法 + 业务理解,三重确认最优K值。
- 警惕球形簇偏好:当数据具有复杂形状时,CH指数可能误导,此时优先选择轮廓系数或DBSCAN。
延伸阅读:也可参考Scikit-learn官方文档中关于calinski_harabasz_score的详细参数说明,以及结合Davies-Bouldin Index进行综合评价。