TL;DR
场景:KMeans 不知道该选多少簇,且不同初始化导致结果漂移。
结论:用轮廓系数在候选 k 上做对比,并用 k-means++ + 合理 n_init 固化稳定性;注意 scikit-learn 1.4 起 n_init 默认变为auto。
产出:可复用的 silhouette 分析图模板 + 初始化参数取值规则 + 常见报错/版本差异速查。
案例:基于轮廓系数来选择 n_clusters
编写代码
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_samples, silhouette_score
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import numpy as np
# 假设X已经是定义好的数据集
# for循环,簇数从2到10,步长为2
for i in range(2, 10, 2):
# 创建图形和子图
fig, (ax1, ax2) = plt.subplots(1, 2)
fig.set_size_inches(18, 7)
# 设置第一个子图的x轴和y轴范围
ax1.set_xlim([-0.1, 1])
ax1.set_ylim([0, X.shape[0] + (i + 1) * 10])
# 生成KMeans模型并拟合数据
clusterer = KMeans(n_clusters=i, random_state=10)
cluster_labels = clusterer.fit_predict(X)
# 计算轮廓系数
silhouette_avg = silhouette_score(X, cluster_labels)
sample_silhouette_values = silhouette_samples(X, cluster_labels)
print(f"簇数 = {i}, 轮廓系数均值 = {silhouette_avg}")
y_lower = 10
for j in range(i):
# 获取第j簇的轮廓系数
ith_cluster_silhouette_values = sample_silhouette_values[cluster_labels == j]
ith_cluster_silhouette_values.sort()
size_cluster_j = ith_cluster_silhouette_values.shape[0]
y_upper = y_lower + size_cluster_j
color = cm.nipy_spectral(float(j) / i)
ax1.fill_betweenx(np.arange(y_lower, y_upper),
ith_cluster_silhouette_values,
facecolor=color, alpha=0.5)
ax1.text(-0.05, y_lower + 0.5 * size_cluster_j, str(j))
y_lower = y_upper + 10
ax1.set_title("不同簇的轮廓图")
ax1.set_xlabel("轮廓系数值")
ax1.set_ylabel("簇类标签")
ax1.axvline(x=silhouette_avg, color="red", linestyle="--")
ax1.set_yticks([])
# 子图2:簇群的散点图
colors = cm.nipy_spectral(cluster_labels.astype(float) / i)
ax2.scatter(X[:, 0], X[:, 1], marker='o', s=8, c=colors)
# 画出簇的质心
centers = clusterer.cluster_centers_
ax2.scatter(centers[:, 0], centers[:, 1], marker='x', c="red", s=200)
ax2.set_title("簇群数据可视化")
ax2.set_xlabel("第一特征的特征空间")
ax2.set_ylabel("第二特征的特征空间")
plt.suptitle(f"样本数据的KMeans轮廓分析--簇数为:{i}", fontsize=14, fontweight='bold')
plt.show()
重要参数-初始质心选择
init
可输入 “k-means++”,“random”或者一个 n 维数组
- 初始化质心的方法,默认”k-means++”
- 输入”k-means++“:一种为 K 均值聚类选择初始聚合中心的聪明的办法,以加速收敛
- 如果输入了 N 维数组,数组的形状应该是(n_clusters,n_features)并给出初始质心
n_init
整数,默认 10
- 使用不同的质心随机初始化的种子来运行 KMeans 算法的次数
- 最终结果会是基于 Inertia 来计算的
- n_init 次连续运行后的最佳输出
random_state
控制随机性,用于复现结果
重要参数-迭代停止
-
max_iter(最大迭代次数):
- 默认值通常为 300 次迭代
- 设置这个参数可以防止算法无限循环
-
tol(容忍度):
- 定义为两次连续迭代间 Inertia 的下降量
- 默认值通常为 1e-4
错误速查
| 症状 | 根因定位 | 修复 |
|---|---|---|
| ValueError: Number of labels is 1 | 聚类结果只有 1 个簇 | 检查 n_clusters 与数据;先保证 n_clusters>=2 |
| 同样的 k,每次运行结果明显变动 | 初始化导致落入不同局部最优 | 固定 random_state;显式提高 n_init |
| 你以为 n_init 默认 10,但结果像只跑了 1 次 | scikit-learn 1.4+ 默认 n_init=‘auto’ | 显式写 n_init=10/20/… |
| ConvergenceWarning: Number of distinct clusters found smaller than n_clusters | 数据中重复点/离散取值过少 | 统计去重后样本数;降低 n_clusters |