KMeans-K-均值聚类
K-Means 是最常用的原型聚类方法之一,其核心思想是:给定簇数 K,通过迭代地执行“样本归属分配”和“簇中心更新”,使簇内平方和最小。与 DBSCAN、HDBSCAN 等基于密度的方法不同,K-Means 需要用户预先给定聚类数,更适合发现近似球状、规模相对均衡的簇结构。
KMeans-K-均值聚类
1. 方法概述
K-Means 是最常用的原型聚类方法之一,其核心思想是:给定簇数 \(K\),通过迭代地执行“样本归属分配”和“簇中心更新”,使簇内平方和最小。与 DBSCAN、HDBSCAN 等基于密度的方法不同,K-Means 需要用户预先给定聚类数,更适合发现近似球状、规模相对均衡的簇结构。
本项目中的 KMeans-K-均值聚类 模块并不是自写 K-Means 迭代器,而是对 sklearn.cluster.KMeans 的工程化封装。当前代码实现的主要特点包括:
- 支持从任意列中选择
label_col作为样本名称展示列; - 支持对数值特征执行
none、minmax、zscore三种预处理; - 支持
k-means++与random两种初始化; - 支持
n_init多次重复初始化并取最优结果; - 可选自动评估 \(K\) 范围,输出 SSE 与轮廓系数曲线;
- 输出归一化空间中心、原始尺度中心、簇汇总表、指标表与聚类图。
与前面若干聚类模块不同,本模块不要求首列必须是样本 ID。上传数据后,程序会自动识别哪些列可以完整转换为数值列,并允许用户在界面中额外指定一列作为 label_col;真正参与聚类的是用户勾选的数值型特征列。
设共有 \(n\) 个样本、\(p\) 个被选中的特征,记参与聚类的原始特征矩阵为
$$ X=(x_{ij})_{n\times p},\quad i=1,2,\ldots,n,\ j=1,2,\ldots,p \tag{1} $$
2. 数据要求与预处理
2.1 数据约束
根据 upload_widget.py、indicators_widget.py 与 data_validator.py 的当前实现,模块对输入数据的真实要求如下:
- 数据表不能为空;
- 样本量至少为 2 行;
- 数据中至少要存在 1 列可完整转为数值的列;
- 被选中的特征列必须存在;
- 特征列不能含非数值或空值;
- 特征列不能是常数列;
- 真正开始计算时,还要求样本数不少于聚类数,即 \(n\ge K\)。
其中 label_col 是可选的。若用户未指定样本名称列,程序会自动生成
$$ \text{样本1},\text{样本2},\ldots,\text{样本}n \tag{2} $$
作为结果表中的样本标识。
2.2 Min-Max 归一化
当 normalize="minmax" 时,程序按列执行线性缩放:
$$ z_{ij}=\frac{x_{ij}-x_j^{\min}}{x_j^{\max}-x_j^{\min}} \tag{3} $$
若某列满足 \(x_j^{\max}=x_j^{\min}\),代码会把分母替换为 1,以避免除零。
2.3 Z-score 标准化
当 normalize="zscore" 时,程序执行
$$ z_{ij}=\frac{x_{ij}-\mu_j}{\sigma_j} \tag{4} $$
其中 \(\mu_j\) 和 \(\sigma_j\) 分别为第 \(j\) 个特征的均值与总体标准差;若 \(\sigma_j=0\),同样会以 1 替代。
若 normalize="none",则直接令
$$ z_{ij}=x_{ij} \tag{5} $$
经预处理后得到用于 K-Means 拟合的特征矩阵
$$ Z=(z_{ij})_{n\times p} \tag{6} $$
2.4 符号说明
| 符号 | 含义 |
|---|---|
| \(n\) | 样本数量 |
| \(p\) | 特征维数 |
| \(K\) | 聚类数 n_clusters |
| \(z_i\) | 第 \(i\) 个样本的预处理后特征向量 |
| \(c_k\) | 第 \(k\) 个簇中心 |
| \(y_i\) | 第 \(i\) 个样本的簇标签 |
| \(\mathcal{G}_k\) | 第 \(k\) 个簇对应的样本集合 |
| \(n_k\) | 第 \(k\) 个簇的样本数 |
| \(\mathrm{SSE}\) | 总簇内平方和 |
| \(R\) | 重复初始化次数 n_init |
3. 核心数学模型
3.1 K-Means 优化目标
K-Means 的目标是寻找 \(K\) 个簇中心,使簇内平方和最小:
$$ \min_{\{\mathcal{G}_k,c_k\}_{k=1}^{K}} \sum_{k=1}^{K}\sum_{z_i\in \mathcal{G}_k}\|z_i-c_k\|_2^2 \tag{7} $$
在 sklearn.cluster.KMeans 中,最终输出的 inertia_ 就是式(7) 对应的目标函数值,也就是项目结果表中的“总簇内平方和”。
3.2 样本分配与中心更新
从算法机理上,K-Means 在每轮迭代中会把样本分配给最近中心:
$$ y_i=\arg\min_{1\le k\le K}\|z_i-c_k\|_2 \tag{8} $$
然后对每个簇重新计算均值中心:
$$ c_k=\frac{1}{n_k}\sum_{i:y_i=k} z_i \tag{9} $$
本项目并未手工实现该迭代,而是把 n_clusters、init、n_init、max_iter、tol 与 random_state 直接传入 sklearn.cluster.KMeans 完成拟合。
3.3 初始化与多次重复拟合
当前界面支持两种初始化方式:
k-means++random
同时支持重复初始化 \(R=\texttt{n\_init}\) 次。若第 \(r\) 次初始化得到的目标函数值记为
$$ \mathrm{SSE}^{(r)}=\sum_{k=1}^{K}\sum_{z_i\in \mathcal{G}_k^{(r)}}\|z_i-c_k^{(r)}\|_2^2 \tag{10} $$
则最终会保留目标函数值最小的那次结果:
$$ r^\ast=\arg\min_{1\le r\le R}\mathrm{SSE}^{(r)} \tag{11} $$
3.4 簇汇总统计量
项目会对每个簇输出样本数、簇内平方和与样本占比。对第 \(k\) 个簇,
$$ n_k=\sum_{i=1}^{n}\mathbf{1}(y_i=k) \tag{12} $$
簇内平方和为
$$ \mathrm{SSE}_k=\sum_{i:y_i=k}\|z_i-c_k\|_2^2 \tag{13} $$
样本占比为
$$ \pi_k=\frac{n_k}{n} \tag{14} $$
因此总簇内平方和满足
$$ \mathrm{SSE}=\sum_{k=1}^{K}\mathrm{SSE}_k \tag{15} $$
3.5 中心反变换
项目不仅输出归一化空间中的 Centers,还会把中心反变换回原始尺度,形成 Centers_Original。
对 Min-Max 归一化,反变换为
$$ c_{kj}^{(\text{orig})}=c_{kj}^{(\text{norm})}\cdot (x_j^{\max}-x_j^{\min})+x_j^{\min} \tag{16} $$
对 Z-score 标准化,反变换为
$$ c_{kj}^{(\text{orig})}=c_{kj}^{(\text{norm})}\cdot \sigma_j+\mu_j \tag{17} $$
若未做归一化,则 Centers_Original 与 Centers 一致。
4. 自动评估 K 范围
4.1 K 范围扫描规则
若勾选 eval_enabled=True,程序会在区间
$$ K\in\{K_{\min}, K_{\min}+\Delta K,\ldots,K_{\max}\} \tag{18} $$
上重复拟合 K-Means。其中
$$ K_{\min}=\max(2,\texttt{eval\_k\_min}),\qquad \Delta K=\max(1,\texttt{eval\_k\_step}) \tag{19} $$
并且代码会进一步把
$$ K_{\max}\leftarrow \min(\texttt{eval\_k\_max},\, n) \tag{20} $$
即扫描上界不会超过样本量。
4.2 SSE 曲线
对每个候选 \(K\),程序记录该模型的 inertia_,也就是
$$ \mathrm{SSE}(K)=\sum_{k=1}^{K}\sum_{z_i\in \mathcal{G}_k}\|z_i-c_k\|_2^2 \tag{21} $$
并据此绘制 elbow_curve.png。该曲线通常用于观察“肘部拐点”。
4.3 轮廓系数曲线
若候选聚类数满足 \(K>1\) 且 \(n>K\),程序尝试计算轮廓系数:
$$ s_i=\frac{b_i-a_i}{\max(a_i,b_i)} \tag{22} $$
$$ \mathrm{Silhouette}(K)=\frac{1}{n}\sum_{i=1}^{n}s_i \tag{23} $$
其中 \(a_i\) 为样本 \(i\) 与同簇样本的平均距离,\(b_i\) 为其到最近其他簇样本的平均距离。该值越大,通常表示聚类分离性越好。
5. 评价指标
对最终选定的聚类数 \(K\),项目会输出以下指标:
5.1 轮廓系数
项目仅在“簇数大于 1 且样本数大于簇数”时才计算轮廓系数,其定义见式(22) 与式(23)。
5.2 Calinski-Harabasz 指数
项目调用 sklearn.metrics.calinski_harabasz_score 计算 CH 指数,可写为
$$ \mathrm{CH}= \frac{\operatorname{tr}(B_K)/(K-1)} {\operatorname{tr}(W_K)/(n-K)} \tag{24} $$
其中 \(B_K\) 与 \(W_K\) 分别表示类间离散矩阵与类内离散矩阵。一般而言,CH 越大越好。
5.3 Davies-Bouldin 指数
项目还调用 sklearn.metrics.davies_bouldin_score 计算 DB 指数。若记第 \(k\) 个簇的平均类内离散度为 \(S_k\),簇 \(k,l\) 中心距离为 \(M_{kl}\),则
$$ R_{kl}=\frac{S_k+S_l}{M_{kl}} \tag{25} $$
$$ \mathrm{DB}=\frac{1}{K}\sum_{k=1}^{K}\max_{l\ne k}R_{kl} \tag{26} $$
一般而言,DB 越小越好。
6. 算法流程
结合当前项目代码,KMeans-K-均值聚类 的实际执行流程如下:
- 用户上传
.xlsx、.xls或.csv文件;CSV 会依次尝试utf-8-sig、utf-8、gbk编码。 - 程序扫描每一列,识别哪些列能够完整转为数值列,作为可选特征集合。
- 在“特征设置”页,用户可选定一个
label_col作为样本名称列,并勾选若干数值型特征参与聚类。 - 程序校验所选特征列是否存在、是否为数值列、是否含空值、是否为常数列。
- 在“算法参数”页设置
n_clusters、init、n_init、max_iter、tol、random_state、normalize以及是否启用K范围评估。 - 若
normalize="minmax"或zscore,则对特征矩阵执行相应预处理。 - 若启用
K范围评估,则先按式(18) 到式(23) 扫描候选 \(K\),生成Evaluation表。 - 调用
sklearn.cluster.KMeans.fit()得到簇标签、簇中心与总簇内平方和。 - 计算簇汇总表、原始尺度簇中心、Silhouette、CH、DB 等指标。
- 绘制聚类散点图;若启用
K范围评估,再额外绘制肘部法与轮廓系数曲线。 - 导出 Excel 文件
kmeans_results.xlsx,并自动生成复现脚本。
7. 关键参数说明
7.1 n_clusters
聚类数,界面允许范围为 2 到 200,默认值为 3。该参数直接决定最终分成多少个簇,也是 K-Means 最核心的先验输入。
7.2 init
初始化方式,当前支持:
k-means++random
默认值为 k-means++。一般而言,k-means++ 能降低糟糕初始化带来的不稳定性。
7.3 n_init
重复初始化次数,默认值为 10。值越大,越有机会找到更优的局部最优解,但计算开销也更高。
7.4 max_iter 与 tol
二者都直接传给 sklearn.cluster.KMeans:
max_iter控制单次初始化下的最大迭代轮数;tol控制收敛阈值。
默认值分别为 300 和 \(10^{-4}\)。
7.5 random_state
界面标签写为“随机种子(0=不固定)”。代码中:
- 当输入值大于 0 时,传入固定随机种子;
- 当输入值为 0 时,实际传入
None,表示不固定随机性。
7.6 normalize
支持:
noneminmaxzscore
若不同特征的量纲差异较大,通常建议优先考虑 minmax 或 zscore。
7.7 eval_enabled、eval_k_min、eval_k_max、eval_k_step
这一组参数控制是否先对多个候选 \(K\) 做扫描评估。需要注意:
- 若
eval_k_max < eval_k_min,评估表会为空; - 实际扫描上界不会超过样本量;
- 只有启用评估时才会生成
Evaluation工作表和两张评估曲线图。
8. 输出结果与导出说明
8.1 结果对象
当前代码返回的核心结果包括:
raw_data:原始输入数据;processed_data:归一化或标准化后的特征矩阵;step_results.labels:样本名称与簇标签;step_results.cluster_summary:每个簇的样本数、簇内平方和、样本占比;step_results.centers:归一化空间簇中心;step_results.centers_original:原始尺度簇中心;step_results.metrics:样本数、特征数、聚类数、总簇内平方和、轮廓系数、CH、DB;step_results.evaluation:\(K\) 范围评估结果;charts:图表路径字典。
8.2 Excel 工作表
根据 _export_excel() 的实现,导出的 Excel 文件包含:
ParametersRawDataProcessedDataLabelsCentersCenters_OriginalClusterSummaryMetricsEvaluation(仅在启用 K 范围评估时存在)Charts
8.3 图表文件
图表保存到结果目录下的 plots/ 子目录中,当前实现可能生成:
cluster_scatter.pngelbow_curve.pngsilhouette_curve.png
其中:
- 若特征数不少于 2,则
cluster_scatter.png使用处理后数据前两维作图; - 若只有 1 个特征,则以该特征为横轴、纵轴固定为 0 绘制单轴聚类散点图;
- 后两张图只有在启用
K范围评估时才会生成。
9. 论文写作建议
9.1 方法描述模板
“本文采用 K-Means 方法对样本进行聚类分析。首先根据研究变量筛选数值型特征,并视量纲情况对特征进行 Min-Max 归一化或 Z-score 标准化。随后在给定聚类数 \(K\) 的条件下,利用 K-Means 最小化簇内平方和,获得各样本的聚类标签与簇中心。为提高初始解稳定性,模型采用多次随机初始化并保留总簇内平方和最小的结果,同时输出轮廓系数、CH 指数与 DB 指数用于评价聚类质量。”
9.2 结果解释模板
结果部分可写为:K-Means 在给定聚类数 \(K\) 条件下输出了各样本的聚类标签、簇中心与聚类评价指标。若轮廓系数较高且 Davies-Bouldin 指数较低,则说明当前聚类结果具有较好的紧凑性与可分性;若各簇样本占比差异明显,则可进一步结合簇中心解释样本结构差异。
9.3 若启用 K 范围评估的写法
“为辅助确定合理的聚类数,本文进一步在若干候选 \(K\) 上重复拟合 K-Means,并分别计算 SSE 与轮廓系数,结合肘部法曲线和轮廓系数曲线综合判断最优聚类数。”
9.4 图表题注模板
- 图 1 K-Means 聚类结果散点图。
- 图 2 K-Means 肘部法曲线。
- 图 3 K-Means 轮廓系数曲线。
- 表 1 各簇样本数、簇内平方和与样本占比。
- 表 2 各簇中心及聚类评价指标。
10. 实现说明与注意事项
- K-Means 假设簇在欧氏空间中近似球状,对细长簇、不同密度簇或含大量噪声的数据并不稳健。
- 该模块当前固定使用欧氏意义下的 K-Means,不支持自定义距离度量。
- 若某列被选为
label_col,它不会再被当作聚类特征;若用户希望同时保留数值 ID 和真实特征,应明确区分这两类字段。 Centers是预处理空间中的中心,解释业务含义时通常应优先使用Centers_Original。eval_enabled只提供辅助选 \(K\) 的曲线,不会自动替用户改写最终的n_clusters;真正训练仍按当前参数中的n_clusters执行。
11. 单篇终审补充
11.1 图题与表题对齐建议
当前 KMeans 模块的真实工作簿包含:
ParametersRawDataProcessedDataLabelsCentersCenters_OriginalClusterSummaryMetricsEvaluation(仅启用 K 范围评估时存在)Charts
这里应特别区分 Metrics 与 Evaluation 的用途。Metrics 是最终一次聚类结果的质量指标,适合作为正文主表;Evaluation 是多组候选 \(K\) 的辅助评估表,更适合作为“选 \(K\) 过程表”或附录表。不要把 Evaluation 当成最终聚类结果表来引用。
图文件保存到结果目录下的 plots/ 子目录,当前实现真实输出:
cluster_scatter.pngelbow_curve.pngsilhouette_curve.png
其中后两张图只有启用 eval_enabled 且评估表非空时才生成。因此论文图题可以写成“K-Means 聚类散点图”“K-Means 肘部法曲线”“K-Means 轮廓系数曲线”,但若本次运行并未启用 K 范围评估,就不应在正文中强行声称程序输出了三张图。
11.2 终审说明
这篇文档最需要避免的误写,是把 KMeans 的图表目录写成与其他聚类算法一样的时间戳子目录。当前实现固定把图保存到本次结果目录下的 plots/,而不是另建 KMeans_plots_<suffix> 目录,这一点应按真实工程口径写。
另一个需要点明的事实是:Excel 导出优先尝试 xlsxwriter,缺失时自动回退到 openpyxl。这不会改变工作表内容,但会影响列宽自适应效果。因此如果用户在不同环境下看到同样的 kmeans_results.xlsx 排版略有差异,这是导出引擎差异,不是算法结果差异。
11.3 全量强化补充
本篇终审补充绑定的真实算法目录为 具体的算法3/聚类与降维/KMeans-K-均值聚类,本次采用的真实结果目录为 具体的算法3/聚类与降维/KMeans-K-均值聚类/results/KMeans-K-均值聚类分析结果_20260329_171309。该目录同时保留了主工作簿、三张图、复现脚本和 repro_inputs,适合作为单轮结果证据。
主结果工作簿为 具体的算法3/聚类与降维/KMeans-K-均值聚类/results/KMeans-K-均值聚类分析结果_20260329_171309/kmeans_results.xlsx,实测工作表如下:
ParametersRawDataProcessedDataLabelsCentersCenters_OriginalClusterSummaryMetricsEvaluationCharts
这套页名说明当前软件确实区分了最终聚类输出与选 \(K\) 辅助评估。论文正文如果写结果表,应优先引用 ClusterSummary、Metrics 和 Centers_Original;若要说明调参过程,再单独引用 Evaluation。把 Evaluation 当成最终结果表,会直接写偏。
当前目录中的真实图文件为:
具体的算法3/聚类与降维/KMeans-K-均值聚类/results/KMeans-K-均值聚类分析结果_20260329_171309/plots/cluster_scatter.png具体的算法3/聚类与降维/KMeans-K-均值聚类/results/KMeans-K-均值聚类分析结果_20260329_171309/plots/elbow_curve.png具体的算法3/聚类与降维/KMeans-K-均值聚类/results/KMeans-K-均值聚类分析结果_20260329_171309/plots/silhouette_curve.png
因此该轮结果可以真实写成“聚类散点图 + 肘部法曲线 + 轮廓系数曲线”三图并存。这里也再次说明 KMeans 当前实现的图目录就是结果目录下的 plots/,而不是另建带算法名前缀的时间戳子目录。
复现实物方面,该目录实际包含:
具体的算法3/聚类与降维/KMeans-K-均值聚类/results/KMeans-K-均值聚类分析结果_20260329_171309/repro_kmeans_k_均值聚类.py具体的算法3/聚类与降维/KMeans-K-均值聚类/results/KMeans-K-均值聚类分析结果_20260329_171309/repro_inputs/window2_kmeans_baseline_input.csv
脚本中已实锤采用 INPUT_FILE = 'repro_inputs/window2_kmeans_baseline_input.csv',并带有基于脚本目录的候选解析逻辑。因此这一轮的真实口径应写成“主结果工作簿已经落地,repro 依赖结果目录内部输入副本可再执行”,而不是写成外部绝对路径驱动。
11. 软件实现核查补充(2026-07)
- 当前主结果目录应写作
具体的算法3/聚类与降维/KMeans-K-均值聚类/results/KMeans-K-均值聚类分析结果_20260329_171309。 - 正文应围绕
FinalSummary、ClusterSummary、Centers、Centers_Original、Metrics、Evaluation、Charts来写。 - 图证应对应
cluster_scatter.png、elbow_curve.png、silhouette_curve.png,并把选 K 过程和最终聚类结果区分开。 - 复现脚本应按
repro_kmeans_k_均值聚类.py + repro_inputs/window2_kmeans_baseline_input.csv的口径说明。