尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

MATLAB凝聚层次聚类实战:从数据准备到结果评估的完整指南

MATLAB凝聚层次聚类实战:从数据准备到结果评估的完整指南 1. 从“小白”到“会用”为什么凝聚层次聚类值得你花时间如果你是第一次接触MATLAB或者对聚类分析这个概念还比较陌生看到“凝聚层次聚类”这个名词可能会有点发怵。别担心这恰恰是它适合作为“小白训练”起点的原因。很多教程一上来就讲K-means告诉你先要指定K值聚成几类但对于一个全新的数据集你怎么知道应该分成几类呢这本身就是一个难题。而凝聚层次聚类Agglomerative Hierarchical Clustering的魅力就在于它不需要你预先指定类别数。它会从“每个数据点自成一类”开始像搭积木一样一步步把最相似的两个类合并最终形成一个清晰的“树状图”Dendrogram。这个图就像一张家族谱系图你可以根据谱系的“亲疏远近”直观地决定在哪里“下刀”切分从而得到你想要的类别数。这个过程非常符合人类的认知直觉我们先看到细节单个点再逐步归纳出更大的结构类别。对于数据分析新手来说这不仅能帮你完成聚类任务更能让你深刻理解数据点之间的关系是如何被量化和组织的。在MATLAB里实现这一切代码简洁到令人惊喜但背后每一步的选择都大有学问。今天我们就抛开那些复杂的数学公式从实际操作的视角手把手带你走通从数据准备、计算距离、选择合并策略、绘制树状图到最终确定分类的完整流程并分享几个我踩过坑才明白的关键细节。2. 环境准备与数据理解你的“原料”是什么在开始写任何代码之前我们必须先搞清楚两件事一是MATLAB的环境二是我们要分析的数据。这就像做饭前要检查灶具和认识食材一样基础但往往被忽略。2.1 MATLAB基础环境确认对于聚类分析我们主要用到的是MATLAB的核心功能和统计与机器学习工具箱。打开MATLAB在命令行窗口输入ver查看已安装的工具箱列表。确保Statistics and Machine Learning Toolbox存在。凝聚层次聚类的核心函数linkage和dendrogram都来自这个工具箱。接下来明确你的工作目录。我习惯为每个小项目单独建一个文件夹比如D:\MATLAB_Projects\Cluster_Demo然后通过MATLAB界面顶部的“当前文件夹”浏览器导航到这个目录或者使用cd命令。这样做的好处是后续生成的数据文件、图表都能规整地保存在一起避免混乱。2.2 数据导入与初步观察聚类分析的质量八成取决于数据本身。我们这里用一个经典的、易于可视化的数据集——鸢尾花Iris数据集来演示。它包含了150个样本每个样本有4个特征花萼长度、花萼宽度、花瓣长度、花瓣宽度和1个标签山鸢尾、变色鸢尾、维吉尼亚鸢尾。虽然我们有标签但在聚类时我们会“假装”不知道标签纯粹用4个特征来聚类最后再用标签验证效果。在MATLAB中加载这个数据集非常简单load fisheriris运行后工作区会出现两个变量meas和species。meas是一个150x4的数值矩阵每一行是一个样本每一列是一个特征。species是一个150x1的细胞数组存储着每个样本对应的种类名称。第一步永远是先看看数据长什么样disp(数据维度) disp(size(meas)) disp(前5个样本的特征值) disp(meas(1:5, :)) disp(对应的种类) disp(species(1:5))通过summary(meas)或min(meas)max(meas)mean(meas)可以快速了解每个特征的取值范围和中心趋势。这一步至关重要因为如果不同特征的数量级差异巨大比如一个特征范围是0-1另一个是1000-10000那么数值大的特征会在距离计算中占据绝对主导地位导致聚类结果失真。鸢尾花数据集的四个特征单位都是厘米量级相近所以我们可以暂时不做标准化处理。但在实际项目中zscore标准化使每个特征均值为0标准差为1通常是必要的第一步。注意很多新手会直接对原始数据跑聚类然后抱怨结果不好。请务必养成先检查数据分布、考虑是否标准化的习惯。你可以用boxplot(meas)画个箱线图一眼就能看出特征间的尺度差异。3. 核心步骤拆解距离、链接与树状图理解了数据之后我们就可以进入凝聚层次聚类的核心三步曲了。这个过程在MATLAB中主要通过三个函数串联完成pdist,linkage,dendrogram。3.1 计算样本间距离pdist函数的选择聚类的本质是把“相似”的点聚在一起。如何量化“相似”答案就是距离。pdist函数就是用来计算所有样本点两两之间距离的。% 计算欧几里得距离直线距离 Y pdist(meas);这行代码执行后Y是一个包含n*(n-1)/2个元素的向量对于150个样本就是11175个值。它以一种压缩格式存储了所有点对的距离。为什么用压缩格式因为距离矩阵是对称的点A到点B的距离等于点B到点A对角线元素为0点到自身的距离压缩格式可以节省近一半的内存。关键选择来了pdist默认使用‘euclidean’欧几里得距离但它还支持很多其他距离度量比如‘cityblock’曼哈顿距离在特征空间里只能沿坐标轴走。‘cosine’余弦距离衡量的是向量方向的差异对绝对大小不敏感常用于文本。‘correlation’相关距离基于皮尔逊相关系数。对于鸢尾花这种数值型特征欧氏距离是最常用且直观的选择。但如果你在处理基因表达数据变化幅度大或文本向量可能需要考虑余弦距离。选择没有绝对的对错但需要与你对数据“相似性”的理解保持一致。3.2 构建聚类树linkage函数的策略有了距离信息linkage函数就开始执行层次聚类的“凝聚”过程了。它需要上面计算出的距离向量Y以及一个指定“如何计算类间距离”的方法。Z linkage(Y, average);这里的Z是一个(n-1) x 3的矩阵它记录了每一次合并的信息。每一行代表一次合并第1列和第2列是被合并的两个类或原始点的编号第3列是这两个类合并时的距离。第二个关键选择链接方法Linkage Method。这是层次聚类的灵魂直接影响树状图的形状和最终聚类结果。‘single’单链接取两类中所有点对距离的最小值。容易形成“链式”结构对噪声和离群点敏感可能把不相似的点连在一起。‘complete’全链接取两类中所有点对距离的最大值。倾向于产生紧凑的、大小相近的类对噪声点不敏感但可能分裂大的类。‘average’平均链接取两类中所有点对距离的平均值。这是最常用、最稳健的方法在单链接和全链接之间取得了很好的平衡也是我上面例子中使用的。‘ward’沃德法合并后能使类内方差增量最小的两类。倾向于产生大小相似的类效果通常很好但要求使用欧氏距离。对于初学者我强烈建议从‘average’开始。你可以尝试运行不同的方法然后观察它们生成的树状图有何不同这是理解算法行为的最佳方式。3.3 可视化聚类过程dendrogram图的解读树状图是层次聚类的“地图”它把linkage输出的合并过程直观地展示出来。figure(‘Position‘ [100, 100, 800, 400]) % 设置图形窗口大小 dendrogram(Z); title(‘鸢尾花数据集凝聚层次聚类树状图 (平均链接)’) xlabel(‘样本索引’) ylabel(‘距离’)运行后你会看到一幅倒置的“树”。底部叶子节点是150个原始样本。越往上树枝合并代表类被聚合。纵轴的高度表示此次合并发生时两类之间的距离。距离越大说明被合并的两个类差异越大。如何从树状图决定分几类你看那些比较长的“垂直树干”。想象用一把水平刀在某个高度切过去与水平线相交的树枝数量就是你得到的聚类数。例如在纵轴距离3的地方横切可能只切到2根主枝那就分成2类在距离1的地方横切可能会切到3根或4根枝那就分成3类或4类。MATLAB的dendrogram函数可以方便地指定显示类别数并返回切割信息% 指定希望显示为30个叶节点便于看图并自动按最大距离阈值切割 T dendrogram(Z, 30, ‘ColorThreshold‘ ‘default‘);‘ColorThreshold‘参数设置一个距离阈值小于此阈值的链接会用同一种颜色显示这实际上就是在进行切割。‘default‘会让MATLAB使用70%的最大链接距离作为阈值。T是返回的每个叶节点所属的类别编号。4. 确定聚类数目与结果评估从“树”到“果”画出了树状图我们知道了聚类的过程但最终要分成几类呢这没有标准答案但有一些方法可以帮助我们做决策。4.1 利用“不一致性系数”寻找自然分界点inconsistent函数可以计算链接的不一致性系数它衡量一次合并与其以下几次合并的平均高度之间的差异。差异越大说明这次合并把两个很不一样的类结合在了一起这可能就是一个自然的分类边界。% 计算不一致性系数深度设为3看当前合并与其下3层合并的比较 I inconsistent(Z, 3); % 查看最后几次合并的不一致性系数 disp(‘最后5次合并的信息[链接距离 不一致性系数 包含的链接数 标准差]’) disp(I(end-4:end, :))通常我们会寻找不一致性系数出现“跳跃”或显著增大的行。你可以画图观察figure; plot(I(:,2), ‘-o‘); % 绘制不一致性系数随合并次数的变化 xlabel(‘合并步骤’); ylabel(‘不一致性系数’); title(‘不一致性系数变化图’); grid on;在图上寻找一个明显的拐点。这个点对应的合并步骤再换算成类别数n - 步骤数可能就是一个合适的聚类数候选。4.2 指定类别数获取聚类结果假设通过观察树状图和不一致性系数我们觉得分成3类比较合理。我们可以使用cluster函数来获取每个样本的类别标签。% 根据链接矩阵Z和最大距离阈值或类别数来创建聚类 % 方法1通过指定‘MaxClust‘参数直接分成3类 T_cluster cluster(Z, ‘MaxClust‘, 3); % 方法2通过指定距离阈值‘Cutoff‘来切割 % 需要从树状图上估算一个距离值比如1.5 % T_cluster cluster(Z, ‘Cutoff‘, 1.5, ‘Criterion‘, ‘distance‘); disp(‘前10个样本的聚类标签’) disp(T_cluster(1:10)‘)现在T_cluster就是一个150x1的向量里面的数字1,2,3分别代表每个样本被分配到的簇。4.3 可视化与评估聚类效果因为我们有真实的物种标签species所以可以进行一个简单的对比评估。最直观的方法是画散点图用聚类结果着色。% 选择两个特征维度进行可视化例如花瓣长度和花瓣宽度 feat1 3; % 花瓣长度在meas中的列索引 feat2 4; % 花瓣宽度 figure(‘Position‘ [100, 100, 1200, 500]); % 子图1根据真实物种标签着色 subplot(1,2,1); gscatter(meas(:, feat1), meas(:, feat2), species); title(‘真实物种分布 (花瓣长度 vs 花瓣宽度)’); xlabel(‘花瓣长度 (cm)’); ylabel(‘花瓣宽度 (cm)’); legend(‘Location‘, ‘best‘); % 子图2根据聚类结果着色 subplot(1,2,2); gscatter(meas(:, feat1), meas(:, feat2), T_cluster); title(‘凝聚层次聚类结果 (3类)’); xlabel(‘花瓣长度 (cm)’); ylabel(‘花瓣宽度 (cm)’); legend(‘Cluster 1‘, ‘Cluster 2‘, ‘Cluster 3‘, ‘Location‘, ‘best‘);通过对比左右两图你可以清晰地看到聚类算法是否成功地将不同物种区分开来。通常山鸢尾setosa能很好地被分离出来而变色鸢尾versicolor和维吉尼亚鸢尾virginica可能会有部分重叠这与它们本身在特征空间上的接近程度有关。量化评估我们可以计算一个简单的“混淆矩阵”来看聚类标签与真实标签的对应关系。但要注意聚类标签的数字1,2,3与真实物种名称没有必然对应关系算法可能把第一类标为2第二类标为1。% 创建一个交叉表 [c, order] confusionmat(species, T_cluster); disp(‘聚类结果与真实标签的交叉表’) disp(c)你需要观察这个矩阵的行真实类别和列聚类类别看看是否每一行的大部分样本都集中在某一列。这能给你一个定量的、直观的效果感知。5. 实战中的关键技巧与避坑指南走通了基本流程并不意味着你就能处理好所有数据。下面这些是我在多次实践中总结出的经验很多是官方文档不会强调的细节。5.1 数据标准化何时做怎么做前面提到特征尺度问题这里展开讲。如果你的特征来自不同传感器比如温度0-100、压力0-1000000、湿度0-1或者像金融数据中股价和交易量不标准化聚类结果就会被大数值特征“绑架”。标准化操作% Z-score标准化 (最常用) meas_zscore zscore(meas); % 或者使用范围标准化到[0,1] meas_minmax (meas - min(meas)) ./ (max(meas) - min(meas)); % 注意上面这行是对整个矩阵操作更稳妥的是逐列处理 % for i 1:size(meas,2) % meas_minmax(:,i) (meas(:,i) - min(meas(:,i))) / (max(meas(:,i)) - min(meas(:,i))); % end经验法则除非你有充分理由相信所有特征同等重要且尺度一致否则先做标准化。做完后重新运行pdist和linkage。你会发现树状图可能和之前大不相同。5.2 处理大规模数据性能与近似方法凝聚层次聚类的时间复杂度是 O(n^3)空间复杂度是 O(n^2)。当样本数n超过几千时计算距离矩阵pdist就可能耗尽内存linkage也会变得极慢。应对策略降维先行使用主成分分析PCA或t-SNE等降维技术将高维数据降到2-3维再进行聚类。这不仅能提速有时还能去除噪声让聚类结构更清晰。[coeff, score, latent] pca(meas_zscore); % 取前两个主成分 meas_pca score(:, 1:2); Y_pca pdist(meas_pca); Z_pca linkage(Y_pca, ‘average‘);采样如果数据允许可以先进行随机采样在子集上运行层次聚类确定大致的类别数和结构再使用其他快速聚类方法如K-means处理全量数据。使用近似算法或更高效的工具箱MATLAB的统计与机器学习工具箱也提供了kmedoids等算法。对于超大规模数据可能需要考虑专门的聚类库或分布式计算框架。5.3 树状图美化与自定义切割默认的dendrogram图在样本多时会显得非常拥挤。除了用dendrogram(Z, 30)限制显示叶节点数量你还可以调整图形颜色、线宽让主枝更突出。编程实现自动切割。一种常见方法是寻找不一致性系数的局部峰值。% 示例寻找不一致性系数大于阈值的链接作为切割点 I inconsistent(Z); threshold 1.0; % 这个阈值需要根据你的数据调整 cut_idx find(I(:,2) threshold); if ~isempty(cut_idx) % 取第一个超过阈值的点从下往上 cut_step cut_idx(1); num_clusters size(Z,1) 1 - cut_step; % 计算此时类别数 T_auto cluster(Z, ‘MaxClust‘, num_clusters); fprintf(‘自动切割建议分为 %d 类。\n‘, num_clusters); end重要提示自动切割方法仅供参考最终决策一定要结合你对业务/数据的理解。树状图本身提供的是一种“多尺度”的视角没有哪个切割点是绝对正确的。5.4 验证与迭代聚类不是一锤子买卖得到聚类结果后不要就此结束。问自己几个问题聚类结果可解释吗查看每个簇的样本特征均值grpstats函数很好用看看是否能给每个簇一个业务上的命名如“高价值客户”、“低活跃度用户”。改变距离度量或链接方法结果稳定吗如果换用‘correlation‘距离或‘ward‘方法大类结构是否保持不变如果完全变了说明你的数据结构可能不那么清晰或者当前参数选择需要谨慎。是否有离群点Outliers在树状图中那些很晚才被合并链接距离特别大的单个点可能就是离群点。你需要决定是剔除它们重新聚类还是将它们单独视为一类。6. 超越基础从可视化到实际应用拓展掌握了基础操作我们可以玩点更深入的让层次聚类不仅仅输出几个标签。6.1 多维数据可视化结合主成分分析PCA当特征多于3个时我们无法在散点图上看到全貌。这时可以先用PCA降维到2维或3维然后在降维后的空间里画出样本点并用层次聚类的结果着色。% 使用标准化后的数据做PCA meas_std zscore(meas); [coeff, score, latent, tsquared, explained] pca(meas_std); % 绘制前两个主成分的散点图用聚类结果着色 figure; scatter(score(:,1), score(:,2), 40, T_cluster, ‘filled‘); xlabel(sprintf(‘第一主成分 (解释方差 %.1f%%)‘, explained(1))); ylabel(sprintf(‘第二主成分 (解释方差 %.1f%%)‘, explained(2))); title(‘PCA降维视图下的聚类结果’); colormap(jet(3)); % 使用jet颜色映射对应3个类 colorbar;这张图能告诉你你的聚类结果在数据的主要变异方向上是否分离良好。如果不同颜色的点混杂在一起说明聚类效果可能不理想或者PCA丢失了用于区分的关键信息。6.2 热图Heatmap展示特征与聚类的关联热图可以同时展示样本聚类行和特征列的信息非常适合观察不同簇的特征模式。% 为了热图美观先对样本按聚类标签排序 [~ idx] sort(T_cluster); meas_sorted meas(idx, :); species_sorted species(idx); % 创建热图 figure(‘Position‘ [100, 100, 800, 600]); imagesc(meas_sorted‘); % 转置让行是特征列是样本 colorbar; xlabel(‘样本 (按聚类排序)’); ylabel(‘特征’); set(gca, ‘YTick‘, 1:4, ‘YTickLabel‘, {‘花萼长‘, ‘花萼宽‘, ‘花瓣长‘, ‘花瓣宽‘}); title(‘鸢尾花特征热图 (行已按聚类结果重排)’); % 添加聚类分界线 cluster_boundaries find(diff(T_cluster(idx)) ~ 0); hold on; for i 1:length(cluster_boundaries) plot([cluster_boundaries(i)0.5, cluster_boundaries(i)0.5], [0.5, 4.5], ‘r-‘, ‘LineWidth‘, 2); end hold off;从热图中你可以清晰地看到属于同一簇的样本其颜色模式即特征值高低是否相似。例如你可能发现Cluster 1的花瓣长度和宽度整体颜色较浅值小而Cluster 3的颜色较深值大。这直接验证了聚类结果的合理性。6.3 将流程封装成可复用的函数当你需要多次对不同数据集进行类似的聚类分析时将流程封装成函数会大大提高效率。function [T, Z, fig_handle] my_hierarchical_cluster(data, linkage_method, num_clusters, do_plot) % MY_HIERARCHICAL_CLUSTER 执行凝聚层次聚类并可视化 % 输入 % data: n x m 数据矩阵 % linkage_method: 链接方法字符串如 ‘average‘ % num_clusters: 期望的聚类数目 % do_plot: 是否绘图 true/false % 输出 % T: n x 1 聚类标签向量 % Z: 链接矩阵 % fig_handle: 图形句柄如果绘图 % 1. 数据标准化 data_std zscore(data); % 2. 计算距离和链接 Y pdist(data_std); Z linkage(Y, linkage_method); % 3. 获取聚类标签 T cluster(Z, ‘MaxClust‘, num_clusters); % 4. 可视化 fig_handle []; if do_plot fig_handle figure(‘Position‘ [100, 100, 1000, 400]); % 子图1: 树状图 subplot(1,2,1); dendrogram(Z, min(30, size(data,1))); % 最多显示30个叶节点 title([‘树状图 (‘, linkage_method, ‘ 链接)’]); xlabel(‘样本’); ylabel(‘距离’); % 子图2: 前两个主成分散点图 subplot(1,2,2); [~ score] pca(data_std); gscatter(score(:,1), score(:,2), T); title([‘PCA视图下的聚类结果 (K‘, num2str(num_clusters), ‘)’]); xlabel(‘PC1’); ylabel(‘PC2’); grid on; end end这样你只需要调用[T, Z, fig] my_hierarchical_cluster(meas, ‘average‘, 3, true);就可以一键完成从标准化到出图的全过程。你可以根据自己的需求继续为这个函数增加输入参数如是否标准化、选择哪些特征作图等和功能。
返回列表