正在加载中...

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

ISODATA-ISODATA

No.120 · 在线教程

ISODATA(Iterative Self-Organizing Data Analysis Technique)通常被理解为一种在 K-Means 基础上引入簇分裂与簇合并机制的自适应聚类方法。与固定簇数的传统 K-Means 不同,ISODATA 会在迭代过程中根据簇内离…

ISODATA-ISODATA

1. 方法概述

ISODATA(Iterative Self-Organizing Data Analysis Technique)通常被理解为一种在 K-Means 基础上引入簇分裂簇合并机制的自适应聚类方法。与固定簇数的传统 K-Means 不同,ISODATA 会在迭代过程中根据簇内离散程度和簇间距离动态调整簇结构,从而在一定程度上实现“边聚类、边修正簇数”。

本项目中的 ISODATA-ISODATA 模块并不是直接调用现成的 ISODATA 库,而是实现了KMeans 初始化 + 迭代重分配 + 小簇清理 + 分裂/合并的自写流程。根据当前代码,模块的核心特征包括:

  1. 先以 sklearn.cluster.KMeans 生成初始簇中心;
  2. 迭代执行样本重分配、删除过小簇并重新分配;
  3. 根据簇内最大标准差与平均距离决定是否分裂;
  4. 根据簇中心距离决定是否合并;
  5. 若某轮既没有分裂也没有合并,且标签不再变化,则提前停止。

设共有 \(n\) 个样本、\(p\) 个参与聚类的数值特征。记原始特征矩阵为

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

当前界面约定第 1 列必须为样本 ID/名称,其余列为数值型特征;指标页默认采用第 1 列以外的全部列参与聚类,当前 UI 实际上并未提供逐列勾选开关。

2. 问题定义与数据预处理

对第 \(i\) 个样本,记其特征向量为 \(x_i\in\mathbb{R}^p\)。项目支持 nonestandardminmax 三种预处理方式。

2.1 Z-score 标准化

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

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

其中 \(\mu_j\) 与 \(\sigma_j\) 分别为第 \(j\) 个特征的均值与标准差。

2.2 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}\)。经预处理后得到实际参与聚类的矩阵

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

2.3 符号说明

符号 含义
\(n\) 样本数量
\(p\) 特征维数
\(K_0\) 初始簇数 clusters
\(K_t\) 第 \(t\) 轮迭代时的簇数
\(z_i\) 第 \(i\) 个样本的预处理后特征向量
\(c_k^{(t)}\) 第 \(t\) 轮第 \(k\) 个簇中心
\(y_i^{(t)}\) 第 \(t\) 轮样本 \(i\) 的簇标签
\(n_k^{(t)}\) 第 \(t\) 轮第 \(k\) 个簇的样本数
\(d_{ik}^{(t)}\) 样本 \(i\) 到第 \(k\) 个簇中心的距离
\(\delta_s\) 分裂标准差阈值 split_std_threshold
\(\delta_m\) 合并距离阈值 merge_threshold
\(n_{\min}\) 最小簇大小 min_cluster_size
\(K_{\max}\) 最大簇数 max_clusters

3. 核心数学模型

3.1 KMeans 初始化

程序首先以用户设定的初始簇数 clusters=K_0 对预处理后的数据执行 KMeans 初始化。其优化目标可写为

$$ \min_{\{G_k,c_k\}_{k=1}^{K_0}} \sum_{k=1}^{K_0}\sum_{z_i\in G_k}\|z_i-c_k\|_2^2 \tag{5} $$

初始化阶段的样本标签由

$$ y_i^{(0)}=\arg\min_{1\le k\le K_0}\|z_i-c_k^{(0)}\|_2 \tag{6} $$

得到。当前代码中,KMeans 固定使用 n_init=10,最大迭代次数直接复用 max_iter,随机性由 random_state 控制。

3.2 迭代重分配与中心重估

在后续每轮迭代中,程序都按最近中心重新分配样本:

$$ y_i^{(t)}=\arg\min_{1\le k\le K_t}\|z_i-c_k^{(t)}\|_2 \tag{7} $$

在标签给定时,第 \(k\) 个簇的中心按样本均值重估:

$$ c_k^{(t+1)}=\frac{1}{n_k^{(t)}}\sum_{i:y_i^{(t)}=k}z_i \tag{8} $$

如果某个簇为空,则当前实现会在重估中心时直接跳过该空簇,不保留空簇中心。

3.3 小簇删除与重新分配

当前实现不是把过小簇标记为噪声,而是将其直接删除后重新分配全部样本。若第 \(k\) 个簇的样本数满足

$$ n_k^{(t)}<n_{\min} \tag{9} $$

则该簇不会被保留。设保留下来的中心集合为 \(\mathcal{C}_{\text{keep}}^{(t)}\),程序会基于这些中心重新对全部样本执行式(7) 的最近中心分配。

这意味着,虽然代码和结果参数中预留了 noise_count 字段,当前实现流程下通常不会真正产生 -1 噪声标签;小簇样本会被重新吸收到其他簇,而不是被丢弃为噪声点。

3.4 簇统计量

对第 \(k\) 个簇,程序计算簇内平均距离

$$ \bar d_k=\frac{1}{n_k}\sum_{i:y_i=k}\|z_i-c_k\|_2 \tag{10} $$

并计算每个特征维度上的标准差向量

$$ s_k=(s_{k1},s_{k2},\ldots,s_{kp}) \tag{11} $$

其中

$$ s_{kj}=\sqrt{\frac{1}{n_k}\sum_{i:y_i=k}(z_{ij}-c_{kj})^2} \tag{12} $$

程序在 Stats 表中额外输出

$$ s_k^{\max}=\max_{1\le j\le p}s_{kj} \tag{13} $$

用于后续分裂判定。

3.5 分裂规则

若启用分裂,即 split_std_threshold > 0,程序会筛选满足以下条件的簇作为分裂候选:

  1. 簇大小至少满足 \(n_k \ge 2n_{\min}\);
  2. 最大标准差满足 \(s_k^{\max}>\delta_s\);
  3. 该簇平均距离大于当前所有非空簇平均距离的总体均值。

设总体平均距离为

$$ \bar d_{\text{all}}=\frac{1}{|\mathcal{K}_{+}|}\sum_{k\in\mathcal{K}_{+}}\bar d_k \tag{14} $$

其中 \(\mathcal{K}_{+}\) 为非空簇集合。若某个簇 \(k\) 满足

$$ n_k\ge 2n_{\min},\qquad s_k^{\max}>\delta_s,\qquad \bar d_k\ge \bar d_{\text{all}} \tag{15} $$

则该簇有资格被分裂。程序会取标准差最大的维度

$$ j_k^*=\arg\max_{1\le j\le p}s_{kj} \tag{16} $$

并沿该维度把原中心 \(c_k\) 拆成两个新中心:

$$ c_k^{(+)}=c_k+\frac{1}{2}s_k^{\max}e_{j_k^*},\qquad c_k^{(-)}=c_k-\frac{1}{2}s_k^{\max}e_{j_k^*} \tag{17} $$

其中 \(e_{j_k^*}\) 为第 \(j_k^*\) 个标准基向量。当前实现还会受最大簇数 \(K_{\max}\) 限制;若本轮继续分裂会使簇数超过上限,则停止增加新簇。

3.6 合并规则

若启用合并,即 merge_threshold > 0,程序会计算任意两个簇中心之间的距离:

$$ D_{ab}=\|c_a-c_b\|_2,\qquad a<b \tag{18} $$

当两簇中心距离满足

$$ D_{ab}<\delta_m \tag{19} $$

时,二者会进入合并候选集合。程序按距离从小到大排序后,采用“每个簇在本轮最多参与一次合并”的策略。若簇 \(a\) 与簇 \(b\) 被合并,则新中心按簇大小加权平均:

$$ c_{ab}=\frac{n_a c_a+n_b c_b}{n_a+n_b} \tag{20} $$

这使得样本数更多的簇对合并后的中心位置影响更大。

3.7 停止条件

程序最多执行 max_iter 轮外层迭代。若相邻两轮的标签完全一致,且本轮没有发生分裂和合并,则提前停止,即满足

$$ y^{(t)}=y^{(t-1)},\qquad \text{split\_count}^{(t)}=0,\qquad \text{merge\_count}^{(t)}=0 \tag{21} $$

时终止。这是当前实现的主要收敛判据。

4. 算法流程

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

  1. 读取数据文件,要求至少两列:第 1 列为样本 ID,其余列为数值型特征。
  2. 上传阶段通过 DataValidator 检查:
    • 数据不能为空;
    • 第 1 列样本名称不能重复;
    • 其余列必须能转成数值且不能含空值;
    • 其余列不能是常数列。
  3. 指标页默认把第 1 列以外的全部列作为聚类特征。
  4. normalization 设置对特征矩阵执行 nonestandardminmax 预处理。
  5. 以 KMeans 生成初始簇标签和初始中心。
  6. 迭代执行最近中心分配、小簇删除并重分配、簇统计计算、分裂和合并。
  7. 若标签不再变化且本轮无分裂/合并,则提前停止;否则继续,直到达到 max_iter
  8. 生成 LabelsSummaryStatsParameters 等结果表。
  9. 当特征数大于 2 时,用 PCA 把数据投影到二维后绘制聚类散点图;当特征数等于 2 时直接用前两维作图;当特征数等于 1 时补零形成单轴散点图。
  10. 导出 Excel 文件和可视化图,并自动生成复现脚本 repro_isodata_isodata.py

5. 关键参数说明

5.1 clusters

初始簇数 \(K_0\),界面允许范围为 11000,默认值为 3。程序会把它截断到不超过样本数的范围内,因此实际初始化簇数为

$$ K_0=\min(\texttt{clusters},n) \tag{22} $$

但最少会保留 1 个簇。

5.2 max_iter

最大迭代次数,界面允许范围为 15000,默认值为 300。它同时影响 KMeans 初始化阶段和后续外层 ISODATA 迭代的最大轮数。

5.3 min_cluster_size

最小簇大小 \(n_{\min}\),界面允许范围为 11000,默认值为 1。若某个簇样本数小于该阈值,程序不会把它保留为独立簇,而是删除后重新分配。

5.4 max_clusters

最大簇数上限,界面允许范围为 01000,默认值为 0。其中 0 表示自动,当前实现会把最大簇数设为

$$ K_{\max}=\max\left(K_0,\ \min\left(n,\ \operatorname{round}(2.5K_0)\right)\right) \tag{23} $$

若用户显式输入正整数,则程序会在不小于 \(K_0\) 且不超过样本数的范围内取该值。

5.5 merge_threshold

合并阈值 \(\delta_m\),界面允许范围为 0.01e6,默认值为 0.0。当其为 0 时,合并功能关闭;当其大于 0 时,中心距离小于该阈值的簇可能被合并。

5.6 split_std_threshold

分裂标准差阈值 \(\delta_s\),界面允许范围为 0.01e6,默认值为 0.0。当其为 0 时,分裂功能关闭;当其大于 0 时,满足式(15) 的簇可能被沿最大标准差方向分裂。

5.7 normalization

预处理方式取值为:

  • none
  • standard
  • minmax

若不同特征量纲差异较大,通常建议优先尝试 standardminmax

5.8 random_state

随机种子。界面中留空表示随机;输入整数时,程序会把该值同时传给 KMeans 初始化和 PCA 二维投影,以提高结果复现性。

6. 评价指标与输出结果解释

程序在主流程中会把结果保存到形如

results/ISODATA-ISODATA分析结果_<时间戳>/

的目录下,文件名通常为:

  1. isodata_result_<时间戳>.xlsx
  2. isodata_plot_<时间戳>.png
  3. repro_isodata_isodata.py
  4. repro_inputs/

当前 Excel 输出结构与前面几个聚类模块不同,固定包含以下工作表:

  1. RawData:原始数据表。
  2. Features:参与聚类的原始数值特征矩阵。需要注意,这里输出的是数值化后的特征,而不是标准化/归一化后的矩阵。
  3. Labels:样本 ID 与最终簇标签。
  4. Summary:每个簇的标签和样本数量。
  5. Stats:每个簇的样本数、平均距离和最大标准差。
  6. Parameters:参数配置以及最终统计量,如 cluster_countnoise_countiterationssplit_totalmerge_totalmax_clusters
  7. Charts:聚类图路径索引。

从结果解释角度看:

  1. Summary 中的 count 反映每个最终簇的规模。
  2. Stats 中的 avg_dist 越小,说明该簇内部越紧凑。
  3. Stats 中的 max_std 越大,说明该簇在某个维度上的离散程度越高,也越有可能触发分裂。
  4. Parameters 中的 iterations 是外层 ISODATA 迭代轮数,不是单独的 KMeans 迭代次数。
  5. split_totalmerge_total 分别表示本次运行累计发生的分裂次数和合并次数。
  6. cluster_count 表示最终非负标签簇数;当前实现下 noise_count 通常为 0。
  7. 可视化图在高维情形下使用 PCA 投影到二维,因此图中的空间位置是二维投影结果,不等于原始高维空间中的真实几何关系。

7. 论文写作模板

7.1 方法描述模板

可将当前项目实现表述为:

“本文采用 ISODATA 聚类方法对样本进行无监督分类。首先对样本特征进行预处理,并以 KMeans 聚类结果作为初始划分。随后在迭代过程中,根据簇中心重新分配样本,删除样本数过少的簇,并依据簇内最大标准差和簇间中心距离分别执行分裂与合并操作。若某轮迭代中簇标签不再变化且未发生新的分裂或合并,则停止计算。最终输出样本聚类标签、各簇样本数量、簇内平均距离、最大标准差以及分裂/合并次数,用于分析样本的自适应聚类结构。”

若需要更贴近本项目工程实现,还可补充说明:本文实现并未将过小簇直接作为噪声剔除,而是把其样本重新分配到其他簇;因此结果更接近“动态调整簇数的 KMeans 扩展版”。

7.2 结果解释模板

结果部分可写为:ISODATA 在迭代过程中通过分裂与合并机制动态调整簇数,因此最终分组结果不仅反映样本间距离结构,也体现了簇规模与簇内离散程度的共同约束。若分裂次数较多,说明初始簇内部存在较强异质性;若合并次数较多,则说明部分簇中心间差异不足。

7.3 表格标题模板

表题可写为:ISODATA 聚类结果及分裂合并统计表。

7.4 图表题注模板

图注可写为:ISODATA 自适应聚类结果与簇中心分布图。

7.5 表格示例

建议列名:簇编号、样本数、簇内平均距离、最大标准差、分裂次数、合并次数、最终标签。

8. 实现说明与注意事项

  1. 当前实现适合希望在 KMeans 基础上引入簇分裂和簇合并机制的场景,尤其适合簇数不完全确定的数据。
  2. 上传阶段要求第 1 列样本名称唯一,其余列必须全部为数值型且不能为常数列。
  3. 当前指标页虽然提示“选择/确认特征列”,但实际实现默认采用第 1 列之外的全部列,没有逐列勾选逻辑;论文中应按实际参与聚类的列集合说明。
  4. merge_threshold=0split_std_threshold=0 时,对应机制会被关闭,此时算法更接近普通 KMeans 迭代重分配流程。
  5. 旧版问题记录文件中曾提到“拆分/合并阈值未生效”,但当前 core/isodata_calculator.py 已实现拆分与合并,论文说明应以当前代码为准。
  6. 当前结果 Excel 不输出标准化/归一化后的特征矩阵,也不输出各簇中心表;若论文需要展示标准化空间中的中心位置,需要额外从代码流程或图形结果补充说明。
  7. 程序预留了 noise_count 统计,但当前实现中小簇样本会被重新分配,因此通常不会得到真正的噪声标签 -1
  8. 二维可视化在高维情况下依赖 PCA 投影,只能作为辅助解释,不能完全代表高维空间中的真实簇形结构。

9. 论文写作建议

论文中建议重点解释 ISODATA 相比 KMeans 的两点扩展:

  1. 簇分裂;
  2. 簇合并。

结果表最好同时报告初始簇数、最终簇数、分裂/合并阈值和最终聚类评价指标。若论文需要强调方法优势,可补充与普通 KMeans 在相同数据上的结果对比。

10. 单篇终审补充

10.1 图题与表题对齐建议

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

  • RawData
  • Features
  • Labels
  • Summary
  • Stats
  • Parameters
  • Charts

这里最需要注意的是,当前实现真实导出的是 Features,而不是很多聚类模块常见的 ProcessedData。因此论文表题若引用该表,更准确的写法应是“ISODATA 参与聚类特征矩阵”或“ISODATA 建模特征表”,不要机械套用其他算法的“预处理后数据表”表题。

图文件由 save_to_excel() 触发生成,真实命名口径可见两类:

  • isodata_plot_<时间戳>.png
  • <xlsx 文件名 stem>_clusters.png

因此图题建议统一写成“ISODATA 聚类结果二维投影图”或“ISODATA 最终聚类分布图”,不要把文件名逐字写进论文;文件名本身在不同导出路径下会有时间戳差异,但图义是稳定的。

10.2 终审说明

这篇文档最容易误写的地方有两个。第一,当前实现虽然属于 ISODATA,但导出结果里并没有单独输出“簇中心表”,而是通过 SummaryStats 和聚类图来体现最终结构,因此论文结果部分不应虚构一个“中心点工作表”。

第二,plot_clusters() 在高维场景下会先对归一化特征做 PCA 二维投影,再绘制 clustercenter 标记。因此图中黑色 X 更准确的解释是“投影空间中的簇中心近似位置”,而不是原始高维空间的真实中心坐标。这个口径需要在论文图注或正文中点明。

10.3 全量强化补充

本次全量强化绑定的真实结果目录为 具体的算法3/聚类与降维/ISODATA-ISODATA/results/ISODATA-ISODATA分析结果_20260329_171259。该目录内主工作簿为 isodata_result_20260329_171259.xlsx,实际工作表为 RawDataFeaturesLabelsSummaryStatsParametersCharts。这说明当前单轮结果仍然没有独立的簇中心工作表,文档正文应继续保持这一写实口径,不能额外虚构“中心表”。

同一目录下实际存在两张图:isodata_plot_20260329_171259.pngisodata_result_20260329_171259_clusters.png。前者对应程序主绘图输出,后者对应按结果文件 stem 生成的聚类投影图;二者都是真实产物,因此论文图题可以统一概括为“ISODATA 聚类二维投影图”和“ISODATA 最终聚类分布图”,但不应把它们误解为不同算法步骤的两种完全独立可视化。

复现脚本为 repro_isodata_isodata.py,目录内 repro_inputs/window2_isodata_baseline_input.csv 真实存在。脚本当前参数写法为 INPUT_FILE = 'repro_inputs/window2_isodata_baseline_input.csv'OUTPUT_FILE = 'isodata_result_20260329_171259.xlsx',并绑定 clusters = 3max_iter = 300min_cluster_size = 1max_clusters = 6merge_threshold = 0.6split_std_threshold = 0.35normalization = 'none'random_state = 11。因此 ISODATA 当前也已经具备相对路径输入副本和单目录 repro 链,工程复现口径是完整的。

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

  • 当前主结果目录应写作 具体的算法3/聚类与降维/ISODATA-ISODATA/results/ISODATA-ISODATA分析结果_20260329_171259
  • 正文应围绕 RawDataFeaturesLabelsSummaryStatsParametersCharts 来写。
  • 图证应对应 isodata_plot_20260329_171259.pngisodata_result_20260329_171259_clusters.png,并把分裂/合并、再分配和中心投影图说明清楚。
  • 复现脚本应按 repro_isodata_isodata.py + repro_inputs/window2_isodata_baseline_input.csv 的口径说明。