正在加载中...

展开本页目录
算法教程MeanShift-MeanShift

MeanShift-MeanShift

No.127 · 在线教程

Mean Shift 是一种典型的基于密度峰值搜索的聚类方法。它不要求用户预先指定聚类数,而是通过在特征空间中不断把样本向局部密度更高的位置平移,最终收敛到若干密度峰,并以这些峰作为簇中心。

MeanShift-MeanShift

1. 方法概述

Mean Shift 是一种典型的基于密度峰值搜索的聚类方法。它不要求用户预先指定聚类数,而是通过在特征空间中不断把样本向局部密度更高的位置平移,最终收敛到若干密度峰,并以这些峰作为簇中心。

本项目中的 MeanShift-MeanShift 模块并不是自写均值漂移迭代器,而是对 sklearn.cluster.MeanShiftsklearn.cluster.estimate_bandwidth 的工程化封装。当前代码的关键特点包括:

  1. 固定使用第 1 列作为样本 ID,后续列为数值特征;
  2. 支持手动输入 bandwidth,也支持根据 quantile/n_samples 自动估计带宽;
  3. 支持 nonestandardminmax 三种预处理方式;
  4. 支持 bin_seedingcluster_allmax_iter 参数;
  5. 输出聚类标签、中心坐标、簇统计、带宽信息与图表。

设共有 \(n\) 个样本、\(p\) 个被选中的特征。记原始特征矩阵为

$$ X=(x_{ij})_{n\times p},\quad i=1,2,\ldots,n,\ j=1,2,\ldots,p \tag{1} $$

其中程序约定第 1 列必须为样本 ID/对象名称列,且该列不能重复。

2. 数据要求与预处理

2.1 数据约束

根据 upload_widget.pyindicators_widget.pydata_validator.py 的实现,模块对输入数据的真实要求如下:

  1. 数据不能为空;
  2. 至少包含两列,即第 1 列对象名称和至少 1 列特征;
  3. 第 1 列对象名称必须唯一;
  4. 第 2 列及以后必须为数值型;
  5. 特征列不能含空值;
  6. 特征列不能是常数列;
  7. 样本数量至少为 2。

2.2 Z-score 标准化

normalization="standard" 时,程序调用 StandardScaler,对每个特征执行

$$ z_{ij}=\frac{x_{ij}-\mu_j}{\sigma_j} \tag{2} $$

2.3 Min-Max 归一化

normalization="minmax" 时,程序调用 MinMaxScaler,执行

$$ z_{ij}=\frac{x_{ij}-x_j^{\min}}{x_j^{\max}-x_j^{\min}} \tag{3} $$

normalization="none",则直接令

$$ z_{ij}=x_{ij} \tag{4} $$

记真正进入 Mean Shift 聚类的特征矩阵为

$$ Z=(z_{ij})_{n\times p} \tag{5} $$

2.4 符号说明

符号 含义
\(n\) 样本数量
\(p\) 特征维数
\(z_i\) 第 \(i\) 个样本的预处理后特征向量
\(h\) 核带宽 bandwidth
\(K_h(\cdot)\) 带宽为 \(h\) 的核函数
\(m(z)\) Mean Shift 向量
\(y_i\) 第 \(i\) 个样本的聚类标签
\(c_k\) 第 \(k\) 个簇中心
\(K\) 最终簇数量

3. 核心数学模型

3.1 核密度思想

Mean Shift 可以理解为在核密度估计框架下寻找概率密度峰值。对任意位置 \(z\),其核密度估计可表示为

$$ \hat f(z)=\frac{1}{nh^p}\sum_{i=1}^{n}K\!\left(\frac{z-z_i}{h}\right) \tag{6} $$

其中 \(h\) 为带宽。带宽越大,密度面越平滑;带宽越小,越容易形成更多局部峰。

3.2 Mean Shift 向量

Mean Shift 方法的更新方向可表示为

$$ m(z)= \frac{\sum_{i=1}^{n} z_i\, g\!\left(\left\|\frac{z-z_i}{h}\right\|^2\right)} {\sum_{i=1}^{n} g\!\left(\left\|\frac{z-z_i}{h}\right\|^2\right)} -z \tag{7} $$

算法不断把当前位置 \(z\) 朝着 \(z+m(z)\) 方向移动,直到收敛到密度峰附近。

3.3 聚类结果形成

当不同样本的漂移轨迹收敛到同一个密度峰时,它们会被分配到同一个簇。最终得到的簇中心可记为

$$ \{c_1,c_2,\ldots,c_K\} \tag{8} $$

第 \(i\) 个样本的簇标签为

$$ y_i\in\{0,1,\ldots,K-1\} \tag{9} $$

cluster_all=False,部分未被归入任何簇的样本在 sklearn 中可能会被标记为

$$ y_i=-1 \tag{10} $$

本项目会在统计表中额外记录 num_noise

4. 项目中的带宽估计逻辑

4.1 手动指定带宽

若用户直接输入 bandwidth,代码会把该值传给 MeanShift。当前要求

$$ h>0 \tag{11} $$

否则会直接报错。

4.2 自动估计带宽

bandwidth 留空,程序会调用

  1. estimate_bandwidth(X, quantile=q, n_samples=s)

其中:

$$ 0<q\le 1 \tag{12} $$

$$ s=\min(\texttt{n\_samples},\, n) \tag{13} $$

n_samples 留空,则直接取全部样本。

4.3 带宽估计失败时的回退

这是当前项目一个很关键的工程细节:若 estimate_bandwidth() 结果不是有限正数,代码会回退为“各特征标准差的平均值”,若该值仍无效,则继续回退到 1.0,即

$$ h \leftarrow \operatorname{mean}\big(\operatorname{std}(Z_{\cdot 1}),\ldots,\operatorname{std}(Z_{\cdot p})\big) \tag{14} $$

若上述值为 0 或无效,再令

$$ h\leftarrow 1.0 \tag{15} $$

因此,项目一定会尽量构造一个可用带宽,而不是因为估计失败直接退出。

5. 评价指标

5.1 簇数量

项目在 Stats 表中记录

$$ K=\text{num\_clusters} \tag{16} $$

即最终得到的簇中心数量。

5.2 轮廓系数

若最终簇数量大于 1,且有效标签样本数足够,程序会调用 silhouette_score 计算轮廓系数。其定义为

$$ s_i=\frac{b_i-a_i}{\max(a_i,b_i)} \tag{17} $$

$$ \mathrm{Silhouette}=\frac{1}{n^\ast}\sum_{i=1}^{n^\ast}s_i \tag{18} $$

其中 \(n^\ast\) 表示参与该指标计算的样本数。需要注意:

  1. cluster_all=True 时,通常全部样本都参与计算;
  2. cluster_all=False 时,代码会先剔除 label=-1 的样本,再计算轮廓系数。

5.3 统计表字段

当前 Stats 表中可能出现的字段包括:

  1. num_clusters
  2. bandwidth_used
  3. quantile
  4. n_samples_for_bandwidth
  5. max_iter
  6. num_noise(仅 cluster_all=False 时)
  7. silhouette_score(仅在可计算时出现)

6. 代码实现细节

6.1 使用的是 sklearn.cluster.MeanShift

本项目没有手工实现均值漂移迭代,而是直接构造

  1. MeanShift(bandwidth=..., bin_seeding=..., cluster_all=..., max_iter=...)

再调用 fit_predict(X) 得到簇标签。

6.2 中心坐标的口径

这是当前模块最容易写错的地方之一。代码中的 centers_df 直接来自

  1. ms.cluster_centers_

ms.cluster_centers_ 是在预处理后的特征空间上得到的。当前实现没有把这些中心点再反变换回原始尺度,因此 Centers 工作表中的中心坐标是:

  1. 原始尺度坐标,当 normalization="none"
  2. 标准化后坐标,当 normalization="standard"
  3. Min-Max 缩放后坐标,当 normalization="minmax"

论文或报告中若要解释中心值的业务含义,需要先注意这一点。

6.3 聚类散点图的口径

当前绘图使用的是 self.features,即原始选中特征值,而不是标准化后的矩阵 X。因此:

  1. 图中的点坐标通常是原始尺度;
  2. Centers 表中的簇中心可能是预处理空间坐标。

这两者口径并不完全一致,是当前代码的实际行为。

7. 算法流程

结合当前项目代码,MeanShift-MeanShift 的实际执行流程如下:

  1. 读取 .xlsx.xls.csv 数据文件;CSV 会依次尝试 utf-8-sigutf-8gbk 编码。
  2. 校验数据结构:首列样本 ID 唯一,其余列必须是无空值数值型特征,且不能有常数列。
  3. 在“特征选择”页从第 2 列开始勾选参与聚类的特征。
  4. 在“方法与参数”页设置 bandwidthquantilen_samplesbin_seedingcluster_allmax_iternormalization
  5. 根据 normalization 执行标准化、区间缩放或不处理。
  6. bandwidth 留空,则先用 estimate_bandwidth 估计带宽;若估计失败,再按式(14) 到式(15) 回退。
  7. 调用 sklearn.cluster.MeanShift.fit_predict() 得到样本簇标签和簇中心。
  8. 计算簇数量、实际带宽、噪声点数量和轮廓系数等统计量。
  9. 生成聚类散点图和簇规模柱状图。
  10. 导出 Excel 文件 meanshift_results_<时间戳>.xlsx,并自动生成复现脚本。

8. 关键参数说明

8.1 bandwidth

核带宽。若用户手动指定,则直接作为 Mean Shift 聚类的关键尺度参数;若留空,则走自动估计流程。

8.2 quantile

用于估计带宽的分位数,当前要求范围为

$$ 0<\text{quantile}\le 1 \tag{19} $$

其值越大,通常估计得到的带宽越大。

8.3 n_samples

估计带宽时使用的样本数。若留空,则使用全部样本;若填写,则实际使用值不会超过总样本量。

8.4 bin_seeding

是否启用 bin_seeding。该选项通常用于加速收敛,但可能改变初始核中心候选点的生成方式。

8.5 cluster_all

是否为全部样本分配簇:

  1. True:通常所有样本都会获得簇标签;
  2. False:部分样本可能被标记为 -1

8.6 max_iter

均值漂移迭代的最大迭代次数,默认值为 300。

8.7 normalization

支持:

  1. none
  2. standard
  3. minmax

当特征量纲差异明显时,一般建议优先考虑 standardminmax

9. 输出结果与导出说明

9.1 Excel 工作表

根据 save_to_excel() 的实现,导出的 Excel 文件包含:

  1. RawData
  2. Features
  3. Clustered
  4. Centers
  5. Stats
  6. Parameters
  7. Charts

其中:

  1. RawData 保存原始完整数据;
  2. Features 保存参与聚类的原始特征矩阵;
  3. Clustered 是在原始数据后附加 cluster_label 的结果表;
  4. Centers 保存簇中心坐标;
  5. Stats 保存聚类统计量;
  6. Parameters 中会记录 bandwidth_used

9.2 图表文件

当前代码会在结果目录的 plots/ 子目录中生成:

  1. cluster_scatter.png
  2. cluster_size.png

其中:

  1. 若特征数不少于 2,则 cluster_scatter.png 使用前两维原始特征作图;
  2. 若只有 1 个特征,则绘制单轴散点图;
  3. cluster_size.png 展示各簇样本数分布。

10. 论文写作建议

10.1 方法描述模板

“本文采用 Mean Shift 方法对样本进行密度聚类分析。首先对选定数值特征进行必要的标准化或区间缩放,并结合核带宽参数构造局部核密度估计;随后通过均值漂移迭代,将样本逐步移动到局部密度峰附近,并据此形成若干聚类中心。与需要预设聚类数的方法不同,Mean Shift 可以根据带宽参数自适应地识别簇的个数。本文进一步输出聚类标签、簇中心、簇规模以及轮廓系数,用于评价聚类结构。”

10.2 结果解释模板

结果部分可写为:若 bandwidth_used 较大,通常会得到更少且更平滑的簇;若簇数量较多且簇规模分布高度不均衡,则说明当前带宽下局部峰较多。若 silhouette_score 较高,通常可认为簇间分离性较好。

10.3 图表题注模板

  • 图 1 Mean Shift 聚类散点图。
  • 图 2 Mean Shift 簇规模分布图。
  • 表 1 Mean Shift 聚类中心与统计结果。

11. 实现说明与注意事项

  1. Mean Shift 对带宽极其敏感,带宽设置不当会导致簇数量过多或过少。
  2. 自动估计带宽只是启发式过程,最终仍建议结合业务场景和图形结果复核。
  3. Centers 工作表中的中心坐标可能处于预处理空间,而聚类散点图使用的是原始特征空间,解释时不要混淆。
  4. cluster_all=False 时,结果中可能出现 label=-1 的未分配样本,需要在后续分析中单独处理。
  5. 当前模块不支持自定义核函数、距离度量或更复杂的带宽自适应策略,论文描述时应按当前实现口径表述。

12. 单篇终审补充

12.1 图题与表题对齐建议

当前 MeanShift 模块的真实工作簿包含:

  • RawData
  • Features
  • Clustered
  • Centers
  • Stats
  • Parameters
  • Charts

其中 Clustered 是最适合正文引用的样本分组结果表,Centers 适合做簇中心补充说明,Stats 则适合汇总带宽、簇数和轮廓系数。不要把 Features 误写成“标准化后特征表”,因为当前实现导出的 Features 实际上是原始选中特征矩阵。

图文件保存在结果目录的 plots/ 子目录,当前实现真实输出:

  • cluster_scatter.png
  • cluster_size.png

因此图题建议分别写成“Mean Shift 聚类散点图”“Mean Shift 簇规模分布图”。两张图都是真实导出图,不需要再泛化成“密度峰值图”或“带宽演化图”。

12.2 终审说明

这篇文档最关键的工程事实,是 Centers 和散点图并不在同一个空间。当前 cluster_centers_ 是在归一化后的 X 上计算得到的,而 cluster_scatter.png 使用的是原始 self.features 前两维作图。因此论文里若把 Centers 的数值直接拿去和散点图坐标逐点对应,会出现解释偏差。

另外,当前 repro 脚本已采用 repro_inputs/... 相对路径,结果目录中可见如 repro_inputs/window1_dbscan_meanshift_input.csv 的输入副本引用。这意味着 MeanShift 现在的复现链路是新框架口径,不应再沿用旧版本绝对路径描述。

12.3 全量强化补充

本篇终审补充绑定的真实算法目录为 具体的算法3/聚类与降维/MeanShift-MeanShift,本次采用的代表性结果目录为 具体的算法3/聚类与降维/MeanShift-MeanShift/results/MeanShift-MeanShift分析结果_20260329_171328。该目录是单轮主结果目录,不是 pytest 的 repro 专用目录。

主结果工作簿为 具体的算法3/聚类与降维/MeanShift-MeanShift/results/MeanShift-MeanShift分析结果_20260329_171328/meanshift_results_20260329_171328.xlsx,实测工作表为:

  • RawData
  • Features
  • Clustered
  • Centers
  • Stats
  • Parameters
  • Charts

这些页名说明当前结果重点是“样本分组 + 中心 + 统计摘要”,而不是密度峰值搜索轨迹。Centers 仍需按预处理空间解释,不能直接拿去和散点图坐标逐项对照。

本轮真实图文件为:

  • 具体的算法3/聚类与降维/MeanShift-MeanShift/results/MeanShift-MeanShift分析结果_20260329_171328/plots/cluster_scatter.png
  • 具体的算法3/聚类与降维/MeanShift-MeanShift/results/MeanShift-MeanShift分析结果_20260329_171328/plots/cluster_size.png

因此本轮可写成“聚类散点图 + 簇规模图”,但不能补写带宽搜索曲线、密度峰值图或核函数演化图。

复现实物方面,该目录实际包含:

  • 具体的算法3/聚类与降维/MeanShift-MeanShift/results/MeanShift-MeanShift分析结果_20260329_171328/repro_meanshift_meanshift.py
  • 具体的算法3/聚类与降维/MeanShift-MeanShift/results/MeanShift-MeanShift分析结果_20260329_171328/repro_inputs/window1_dbscan_meanshift_input.csv

脚本中明确写成 INPUT_FILE = 'repro_inputs/window1_dbscan_meanshift_input.csv',且输出目录按脚本目录解析。因此这一轮应描述为“可迁移的相对路径复现入口”,而不是仍依赖原始上传绝对路径。

11. 软件实现核查补充(2026-07)

  • 当前主结果目录应写作 具体的算法3/聚类与降维/MeanShift-MeanShift/results/MeanShift-MeanShift分析结果_20260329_171328
  • 正文应围绕 CentersStatsParametersCharts 来写。
  • 图证应对应 cluster_scatter.pngcluster_size.png,并把带宽聚类与簇规模分开说明。
  • 复现脚本应按 repro_meanshift_meanshift.py + repro_inputs/window1_dbscan_meanshift_input.csv 的口径说明。