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

控制随机性,用于复现结果

重要参数-迭代停止

  1. max_iter(最大迭代次数)

    • 默认值通常为 300 次迭代
    • 设置这个参数可以防止算法无限循环
  2. 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