據(jù)到譜系圖)
簡介基于層次聚類HC的數(shù)據(jù)聚類可視化MATLAB代碼配套Excel格式示例數(shù)據(jù)適合機(jī)器學(xué)習(xí)入門讀者、數(shù)據(jù)挖掘課程設(shè)計者以及需要快速驗證聚類效果的算法工程師。資源圍繞“讀入Excel數(shù)據(jù)—執(zhí)行層次聚類—可視化樹狀圖與簇劃分”這一主線便于理解不同距離度量與連接準(zhǔn)則對聚類結(jié)果的影響也能直接替換為自己的數(shù)據(jù)表進(jìn)行實驗。壓縮包約338KB以MATLAB腳本和Excel數(shù)據(jù)文件為主未單列文件總數(shù)包體輕量、結(jié)構(gòu)簡明便于按需修改目前已有120人學(xué)習(xí)/下載。對剛接觸聚類分析的同學(xué)而言這份代碼省去了從零搭建流程、處理數(shù)據(jù)讀寫與繪圖細(xì)節(jié)的麻煩可作為課程作業(yè)、論文復(fù)現(xiàn)或小型項目的基線方案幫助快速輸出可解釋的聚類結(jié)果。1. 層次聚類可視化這份Matlab工程把Excel數(shù)據(jù)變成可直接解讀的譜系圖層次聚類HC在數(shù)據(jù)分析里常常被當(dāng)成“聽過但沒用過”的算法K-Means要提前拍腦袋定K、對初始點(diǎn)敏感而層次聚類不需要預(yù)設(shè)類別數(shù)跑完一張譜系圖就能看清數(shù)據(jù)的內(nèi)在結(jié)構(gòu)。這份基于Matlab的層次聚類可視化工程把Excel表格作為唯一數(shù)據(jù)入口走完“讀取、標(biāo)準(zhǔn)化、距離計算、聚類、譜系圖、回寫標(biāo)簽”的完整鏈路輸出物是一張帶大簇顏色標(biāo)注的聚類樹和一份每個樣本對應(yīng)的分組編號。適合三類人做用戶或商品分群的業(yè)務(wù)分析人員、需要快速驗證樣本可分性的研究者、想在最小Matlab工程上做二次開發(fā)的初學(xué)者。2. 項目結(jié)構(gòu)與技術(shù)選型為什么是層次聚類MatlabExcel2.1 這份資源到底解決什么問題先把這個工程的位置擺清楚。它不是一個從零實現(xiàn)層次聚類算法的教學(xué)代碼而是一個把Matlab統(tǒng)計工具箱里現(xiàn)成的pdist、linkage、dendrogram、cluster四個函數(shù)串成完整分析鏈路的落地工程。對使用者來說最直接的價值是你只需要準(zhǔn)備一份格式正確的Excel改一行文件路徑就能看到聚類結(jié)果。我對這個工程做完拆解之后的評價是它更像一個分析“骨架”——所有核心步驟都有代碼實現(xiàn)但具體參數(shù)聚類方法、簇數(shù)、顏色閾值都留給你根據(jù)實際數(shù)據(jù)調(diào)整。舉一個實際場景。某公司在給用戶做分群原始特征是Excel里的消費(fèi)金額、訪問次數(shù)、停留時長和轉(zhuǎn)化率一共800多條記錄。如果用K-Means第一步就得定K而且改一次K要重跑一次換成層次聚類的方案跑完直接看譜系圖整棵樹有兩個明顯的高度斷層對應(yīng)三類用戶于是把Cutoff設(shè)成斷層高度三類用戶自然就出來了。這就是這份資源的核心定位讓聚類從“憑經(jīng)驗猜K”變成“看圖定K”。對于還在糾結(jié)“這份代碼跑出來到底長什么樣”的人提前給個預(yù)期控制臺會打印出樣本數(shù)、特征數(shù)和cophenet相關(guān)系數(shù)圖形窗口會彈出一棵從下往上合并的樹狀圖同一大簇的分支用同一顏色result目錄里會多出一張譜系圖和一份帶分組標(biāo)簽的CSV文件。這些東西加起來就是一次完整的層次聚類分析交付物。2.2 目錄結(jié)構(gòu)與關(guān)鍵文件職責(zé)整個工程的文件布局非常緊湊拿到手里一眼能看明白分工hc-cluster-visualization/ ├── main.m % 唯一入口配置參數(shù)按步驟執(zhí)行聚類鏈路 ├── load_data.m % 讀取Excel檢查列類型執(zhí)行標(biāo)準(zhǔn)化 ├── plot_dendrogram.m % 繪制譜系圖支持自定義顏色閾值 ├── cluster_assign.m % 將聚類樹轉(zhuǎn)換為每個樣本的類別標(biāo)簽 ├── data/ │ └── sample_data.xlsx % 示例數(shù)據(jù)樣本ID 多個數(shù)值特征列 └── result/ └── dendrogram.fig % 運(yùn)行后生成的譜系圖我實際跑工程時只在main.m一個文件里做調(diào)整。路徑、sheet名、聚類方法、是否強(qiáng)制指定簇數(shù)都在文件開頭的配置區(qū)修改。其余三個函數(shù)文件除了改圖和改標(biāo)簽顏色外基本不動。這種“單入口配置、少量函數(shù)分工”的結(jié)構(gòu)對二次開發(fā)很友好你想換數(shù)據(jù)格式只改load_data.m你想改可視化風(fēng)格只改plot_dendrogram.m其他部分完全不用碰。各文件的分工在工程里是明確分離的main.m負(fù)責(zé)流程編排它不關(guān)心算法細(xì)節(jié)load_data.m把外部數(shù)據(jù)變成內(nèi)存里的數(shù)值矩陣屏蔽了Excel格式差異cluster_assign.m把linkage生成的層次樹翻譯成人能讀懂的類別標(biāo)簽。這種各司其職的劃分讓代碼既好調(diào)試也好擴(kuò)展。如果某天你想把入口換成CSV或者數(shù)據(jù)庫只需要替換load_data.m一個函數(shù)即可。2.3 技術(shù)選型的三點(diǎn)理由第一算法層面為什么用層次聚類而不是K-Means。K-Means要求預(yù)先給定K值且對初始中心敏感同一份數(shù)據(jù)跑兩次可能有不同結(jié)果層次聚類是確定性算法同一份數(shù)據(jù)用同樣的距離和連接方法跑多少次結(jié)構(gòu)都一樣。更關(guān)鍵的是層次聚類會生成完整的合并樹你可以執(zhí)行完聚類之后再決定從哪個高度切分這個特性在探索性數(shù)據(jù)分析里價值極高。Excel里幾十個特征列互相之間的遠(yuǎn)近關(guān)系用譜系圖一次看全這是其他聚類方法很難給到的體驗。第二工具層面為什么選Matlab。在聚類這個細(xì)分場景Matlab統(tǒng)計與機(jī)器學(xué)習(xí)工具箱提供了一套完整的函數(shù)鏈pdist負(fù)責(zé)兩兩距離linkage負(fù)責(zé)構(gòu)建層次樹dendrogram負(fù)責(zé)繪圖cluster負(fù)責(zé)按數(shù)量或高度切樹——四個函數(shù)恰好覆蓋一次聚類分析的全部環(huán)節(jié)。相比Python用SciPy時需要自己處理壓縮距離矩陣和譜系圖對象Matlab的默認(rèn)參數(shù)更少、報錯更直接對剛接觸聚類的人來說門檻更低。這也是很多教學(xué)場景和業(yè)務(wù)快速驗證都選擇Matlab的原因。第三數(shù)據(jù)層面為什么鎖定Excel。業(yè)務(wù)方手里的大多數(shù)數(shù)據(jù)最終都會匯總成Excelreadtable可以零配置讀取xlsx/xls文件不需要建數(shù)據(jù)庫、寫SQL把文件丟進(jìn)data/目錄就能跑。對于那些一天要試多批數(shù)據(jù)的場景Excel幾乎是你能想到的最順手的入口。這里也可以補(bǔ)充一句這份工程本質(zhì)上是Matlab聚類能力的一個輕量“插件化”封裝它不替代Matlab本身而是把常用的聚類流程固定成一套可復(fù)用步驟——你先裝好Matlab這個“軟件”再把這套工程當(dāng)成“插件”來使這正是它好用的原因。單從層次聚類的實現(xiàn)難度來看從零寫一個需要處理“簇間距離更新、樹結(jié)構(gòu)保存、譜系圖坐標(biāo)計算”三個難題沒有幾百行代碼下不來。這份工程聰明的地方在于把這些難題全部交給了Matlab內(nèi)置函數(shù)保留下來的是數(shù)據(jù)分析本身數(shù)據(jù)怎么讀入、特征怎么標(biāo)準(zhǔn)化、結(jié)果怎么解讀。不重復(fù)造輪子的思路對今天做數(shù)據(jù)工作的開發(fā)者來說其實更受用——你的精力應(yīng)該花在業(yè)務(wù)問題上而不是重新實現(xiàn)一遍已有算法。3. 核心代碼拆解從Excel讀入到聚類譜系圖輸出的完整鏈路3.1 數(shù)據(jù)讀取從Excel到干凈的數(shù)值矩陣load_data.m承擔(dān)了整個工程的數(shù)據(jù)入口邏輯。它要做兩件事把Excel中參與聚類的數(shù)值列提取出來同時保留每行對應(yīng)的樣本名稱。來看核心實現(xiàn)function [X, labels, var_names] load_data(excel_path, sheet_name) % 讀取Excel指定Sheet為表格對象 raw_table readtable(excel_path, Sheet, sheet_name); % 第1列約定為樣本名稱字符串其余列作為聚類特征 labels raw_table{:, 1}; X raw_table{:, 2:end}; % 逐列做標(biāo)準(zhǔn)化避免量綱差異主導(dǎo)距離計算 X zscore(X); % 返回數(shù)值特征列名方便后續(xù)繪圖標(biāo)注橫縱軸 var_names raw_table.Properties.VariableNames(2:end); end這段代碼里的readtable會智能識別每列類型文本列自動變成cell數(shù)組數(shù)值列自動變成double數(shù)組。raw_table{:, 2:end}取出的是一個數(shù)值矩陣這里隱含一個約定Excel的第二列到最后一列必須全部是數(shù)值型。如果中間混入文本X的類型就不是double下一步pdist會直接報錯。zscore按列把均值歸零、標(biāo)準(zhǔn)差歸一這是層次聚類里幾乎必做的一步否則“銷售額”這種大數(shù)值列會壓過“轉(zhuǎn)化率”這種小數(shù)值列。多說一句zscore默認(rèn)按列計算和我們希望的“每個特征各自標(biāo)準(zhǔn)化”完全一致。如果拿到一份量綱差異很大的Excel這行代碼就是決定聚類結(jié)果是否合理的關(guān)鍵。常見做法是先把X備份一份原始值因為標(biāo)準(zhǔn)化之后的矩陣已經(jīng)丟失了業(yè)務(wù)單位后續(xù)畫散點(diǎn)圖如果用原始值會更好解釋。3.2 聚類核心鏈路距離矩陣、層次樹與譜系圖這是工程里最關(guān)鍵的十幾行全部集中在main.m中。邏輯上分三步先求樣本兩兩距離再按距離構(gòu)建層次聚類樹最后把樹畫成譜系圖。% 計算樣本間距離返回壓縮距離向量 D pdist(X, euclidean); % 使用Ward方差最小化策略構(gòu)建層次聚類樹 Z linkage(D, ward); % 繪制譜系圖并讓大簇自動上色 figure(Position, [100, 100, 900, 600]); dendrogram(Z, Labels, labels, ColorThreshold, default);pdist返回的不是完整的N階矩陣而是只保存三角形下三角部分的壓縮向量這在樣本量上千時能省下一大塊內(nèi)存。linkage的第二個參數(shù)ward是最常用的合并策略每次合并使簇內(nèi)離差平方和的增量最小生成緊湊的簇如果你發(fā)現(xiàn)數(shù)據(jù)有明顯長尾可以改成average。dendrogram的ColorThreshold指定了樹干著色的高度閾值設(shè)成default時Matlab會按樹的最大高度自動分級上色不同大簇一眼就能區(qū)分。有一個容易被忽略的點(diǎn)dendrogram默認(rèn)最多顯示30個葉節(jié)點(diǎn)。如果你的數(shù)據(jù)只有十幾個樣本全部顯示沒問題數(shù)據(jù)到了50個以上整個圖會非常擠標(biāo)簽全部疊在一起。工程里的標(biāo)準(zhǔn)處理方式是控制顯示數(shù)量N size(X, 1); if N 30 dendrogram(Z, 30, Labels, labels, ColorThreshold, default); else dendrogram(Z, Labels, labels, ColorThreshold, default); end第二個參數(shù)30的含義是“只顯示樹中最新的30個葉節(jié)點(diǎn)”其余節(jié)點(diǎn)被折疊。這不會改變聚類樹本身只是讓圖更可讀。如果要把聚類分析結(jié)果用于匯報傳統(tǒng)做法是導(dǎo)出一張高分辨率的PNG。新版Matlab里用exportgraphics更干凈exportgraphics(gcf, result/dendrogram.png, Resolution, 300);這條指令在R2020a以后的版本都能用替代了過去容易出問題的print加-dpng組合。300dpi的輸出可以直接放進(jìn)報告或PPT里比.fig文件通用得多。3.3 從樹到標(biāo)簽聚類結(jié)果如何回寫樣本譜系圖給人看cluster函數(shù)則負(fù)責(zé)把樹變成機(jī)器可讀的標(biāo)簽。仍以main.m中的代碼為例% 方式一指定最多類別數(shù) k 3; category cluster(Z, MaxClust, k); % 方式二按樹的高度閾值切分 cutoff 0.6 * max(Z(:, 3)); category cluster(Z, Cutoff, cutoff); % 評估計算樹對原始距離的保留程度 c cophenet(Z, D); fprintf(cophenetic correlation coefficient: %.3f\n, c);MaxClust和Cutoff這兩種切法語義差異很大。MaxClust, 3表示從樹頂部向下剪最終類別數(shù)不超過3如果樹頂層的兩個大簇距離過遠(yuǎn)函數(shù)會自動把類別數(shù)降到2這往往讓習(xí)慣了K-Means的人困惑。Cutoff則是按距離閾值剪枝——所有距離大于閾值的分支被拆開得到的簇數(shù)是數(shù)據(jù)決定的而不是人決定的。實際業(yè)務(wù)里如果已經(jīng)通過譜系圖看到了清晰的斷層高度我會把Cutoff設(shè)成斷層附近的數(shù)值這樣得到的結(jié)果最符合數(shù)據(jù)本身的分布。cophenet系數(shù)的作用是檢驗距離矩陣被樹結(jié)構(gòu)保留了多少通常0.6以上可以認(rèn)為聚類樹可信低于這個值說明數(shù)據(jù)本身沒有明顯的層次結(jié)構(gòu)繼續(xù)分簇意義不大。最后把標(biāo)簽寫回并落盤這一步在工程里由cluster_assign.m完成result_table table(labels, category, ... VariableNames, {SampleID, Cluster}); writetable(result_table, result/cluster_result.csv); % 用前兩個特征畫散點(diǎn)著色圖 figure; gscatter(X(:,1), X(:,2), category); xlabel(var_names{1}); ylabel(var_names{2}); grid on;gscatter按分類變量自動上色不需要手動寫循環(huán)。注意此時X已經(jīng)被zscore標(biāo)準(zhǔn)化散點(diǎn)圖的橫縱軸數(shù)值已經(jīng)沒有原來的業(yè)務(wù)單位解釋時要說明這是標(biāo)準(zhǔn)化后的分布。如果希望散點(diǎn)圖顯示原始數(shù)值需要在標(biāo)準(zhǔn)化之前備份一份原始矩陣。整個回寫過程的優(yōu)勢在于它把可視化結(jié)果和數(shù)據(jù)分析無縫銜接了起來——譜系圖告訴你看結(jié)構(gòu)CSV告訴你可以繼續(xù)往下做統(tǒng)計建模。4. 跑通全流程Excel格式確認(rèn)、運(yùn)行步驟與參數(shù)微調(diào)4.1 Excel數(shù)據(jù)格式約定這一節(jié)把數(shù)據(jù)格式拆得細(xì)一點(diǎn)你可以直接照著準(zhǔn)備。Excel文件的要求有三條A1單元格開始第一行是列名第一列是樣本標(biāo)識文本形式比如用戶ID、商品SKU、城市名第二列到最后一列必須是數(shù)值型特征。一個可以正常讀入的示例SampleID Amount(萬元) Visits Conversion(%) U001 12.5 45 3.2 U002 8.3 22 1.8 U003 20.1 67 5.1這個表有一個容易翻車的地方列名里的括號和百分號不影響readtable讀取但如果某列有空單元格readtable會自動填入NaN。NaN對zscore不致命但pdist會直接報錯。所以拿到Excel之后先看一眼有沒有空行或空列。我一般會在load_data.m里臨時加一行檢查fprintf(樣本數(shù): %d, 特征數(shù): %d, 含NaN單元格數(shù): %d\n, ... size(X,1), size(X,2), sum(isnan(X(:))));如果含NaN單元格數(shù)不為零就要回Excel補(bǔ)數(shù)或刪除對應(yīng)行。另一個常見問題是表頭占了兩行比如第一行是標(biāo)題、第二行才是列名。解決方案是readtable增加NumHeaderLines, 2參數(shù)或者在Excel里先合并單元格、整理成單行表頭再跑。4.2 運(yùn)行全流程的五步操作整個跑通流程只需要五步。第一步把Excel文件放進(jìn)data/目錄文件名不要帶中文和空格避免老版本Matlab對路徑解析出錯。第二步打開main.m修改開頭的配置參數(shù)excel_path data/sample_data.xlsx; sheet_name Sheet1; linkage_method ward; % ward/average/complete/single distance_metric euclidean; color_threshold default; % 或者填寫數(shù)值作為著色閾值第三步直接運(yùn)行整個腳本。如果一切正常命令行會打印出樣本數(shù)、特征數(shù)和cophenet系數(shù)Figure窗口彈出譜系圖。第四步查看result/目錄確認(rèn)生成了dendrogram.fig和cluster_result.csv。第五步用表格軟件打開cluster_result.csv核對每行樣本所屬的簇編號是否和譜系圖里的大簇目測一致。這五步看著簡單但有一個容易忽略的點(diǎn)運(yùn)行前確認(rèn)當(dāng)前目錄是工程根目錄。很多人直接在編輯器里打開main.m忘記把工作目錄切到工程文件夾導(dǎo)致data/sample_data.xlsx這個相對路徑找不到報錯“文件或目錄不存在”。這類問題排查起來很費(fèi)時間運(yùn)行前看一眼工作目錄是最有效的預(yù)防方式。另外腳本運(yùn)行中如果報錯中斷多半是數(shù)據(jù)格式問題優(yōu)先檢查第4.1節(jié)提到的兩類情況。4.3 聚類參數(shù)選擇與結(jié)果驗證這份資源留出來的可調(diào)參數(shù)不多但每個參數(shù)的改動都會明顯改變結(jié)果。下面按經(jīng)驗整理了一張參數(shù)表參數(shù)位置可選值說明pdist距離euclidean/cityblock/cosine連續(xù)數(shù)據(jù)默認(rèn)歐氏含奇異值用曼哈頓文本或方向類特征用余弦linkage方法ward/average/complete/singleward適合緊湊簇average抗異常值single慎用易鏈?zhǔn)胶喜olorThresholddefault/ 具體高度值控制譜系圖大簇著色值越小顏色區(qū)分越碎cluster切法MaxClust/CutoffMaxClust指定最多簇數(shù)Cutoff按樹高切分簇數(shù)由數(shù)據(jù)決定至于結(jié)果怎么驗證推薦兩種手邊就能做的辦法。第一種是看cophenet系數(shù)低于0.6時考慮換linkage方法。第二種是對照業(yè)務(wù)常識檢查簇的特點(diǎn)把cluster_result.csv按簇號分組計算每個簇的特征均值看是否滿足你對“這幾類樣本應(yīng)該有差異”的預(yù)期。比如用戶分群里第1簇的消費(fèi)金額均值明顯高于其他簇那這個分簇結(jié)果才有業(yè)務(wù)解釋意義。如果某簇在全部特征上幾乎和另一簇完全重合說明聚類過度切分了需要調(diào)低切分?jǐn)?shù)或把Cutoff閾值調(diào)高讓樹合并更徹底。4.4 從譜系圖讀取“斷層”并確定最佳聚類數(shù)譜系圖的作用不只是展示更是一個切割決策工具。樹的高度差異在圖上呈現(xiàn)出“長枝”和“短枝”的交界也就是斷層。實際操作中我會在譜系圖上找到最長的那幾根豎線把明顯低于它們的分叉全部剪掉剩下的分支數(shù)量就是合理的聚類數(shù)。這個操作和cluster函數(shù)的Cutoff參數(shù)是對應(yīng)的Cutoff, h把橫線畫在高度h處與橫向分支相交的數(shù)量就是聚類數(shù)。能自動計算這個數(shù)量代碼里可以這樣表達(dá)% 按某個高度切樹并統(tǒng)計簇數(shù) tmp_cluster cluster(Z, Cutoff, cutoff); num_groups length(unique(tmp_cluster)); fprintf(Cutoff%.2f時得到%d個簇\n, cutoff, num_groups);這個方法在探索性分析里幾乎百試百靈。相比K-Means需要畫肘部圖找拐點(diǎn)基于譜系圖斷層的判斷對異常值更穩(wěn)。還有一個更簡單的經(jīng)驗把cutoff從大到小掃一遍記錄每次的簇數(shù)畫一張“cutoff-簇數(shù)”折線圖平緩段的轉(zhuǎn)折點(diǎn)就是比較合適的切樹位置。當(dāng)你在報告里寫“本數(shù)據(jù)集分成三類”別人問你怎么確定的你直接說“譜系圖斷層高度配合閾值掃描”專業(yè)感完全不一樣。5. 踩坑與排查Matlab層次聚類實戰(zhàn)高頻問題記錄5.1 pdist報錯數(shù)據(jù)里有文本或NaN現(xiàn)象運(yùn)行pdist(X, euclidean)時命令行拋出錯誤提示輸入不是數(shù)值矩陣或包含NaN。原因Excel里第二列之后混入了文本單元格比如填了“暫無”兩個字或者存在空單元格被readtable讀成了NaN。zscore遇到NaN會原樣保留但pdist在算距離時無法處理缺失值直接中斷。解決在load_data.m加入剔除非數(shù)值列的檢查numeric_cols varfun(isnumeric, raw_table, OutputFormat, uniform); X raw_table{:, numeric_cols(2:end)}; if sum(~numeric_cols) 1 warning(已自動剔除非數(shù)值列%s, ... strjoin(raw_table.Properties.VariableNames(~numeric_cols), , )); end這樣腳本遇到壞數(shù)據(jù)不會直接崩而是把能用的數(shù)值列挑出來繼續(xù)跑。需要說明的是這個處理會在控制臺打印警告信息跑通后記得回Excel把文本單元格改成數(shù)字或者確認(rèn)這些列本來就該剔除。5.2 聚類結(jié)果被某個量綱大的特征牽著走現(xiàn)象聚類后每一簇的差異主要體現(xiàn)在“銷售額”這一類數(shù)值很大的特征上其他特征在簇間幾乎一樣譜系圖看起來兩個大簇被一條長支硬生生隔開。原因沒有做標(biāo)準(zhǔn)化歐氏距離里大數(shù)值列占據(jù)絕對主導(dǎo)地位。比如“銷售額”單位是萬元數(shù)值是幾十“轉(zhuǎn)化率”是百分比數(shù)值是個位數(shù)兩列對距離的貢獻(xiàn)不在一個數(shù)量級上。解決在進(jìn)入pdist之前對X做zscore。這份工程自帶的load_data.m已經(jīng)做了標(biāo)準(zhǔn)化但如果你自己改寫讀取邏輯很容易漏掉這一行。注意zscore默認(rèn)按列操作和“每個特征單獨(dú)歸一化”的目標(biāo)正好匹配不需要額外加參數(shù)。5.3 譜系圖標(biāo)簽重疊成一團(tuán)現(xiàn)象樣本超過40個后譜系圖底部標(biāo)簽橫七豎八疊在一起沒法讀清某個樣本屬于哪條分支。原因所有樣本名稱被強(qiáng)制畫在x軸葉節(jié)點(diǎn)密度高導(dǎo)致標(biāo)簽互相遮蓋。解決用dendrogram(Z, 30)限制顯示最近合并的30個葉節(jié)點(diǎn)或者把標(biāo)簽旋轉(zhuǎn)45度set(gca, XTickLabelRotation, 45)。還有一種情況是標(biāo)簽本身太長可以在readtable之后對labels做一次截斷處理。業(yè)務(wù)匯報場景我一般直接限制葉節(jié)點(diǎn)數(shù)量因為多數(shù)情況下只需要展示大簇結(jié)構(gòu)不需要把每個樣本名都露出來如果真要展示全部配合導(dǎo)出PNG比在屏幕上拖動窗口體驗好得多。5.4 MaxClust返回的類別數(shù)比指定值少現(xiàn)象設(shè)置了MaxClust, 3但category里只有2類和預(yù)期不符。原因MaxClust是上限而不是目標(biāo)值。當(dāng)樹頂層兩個大簇的距離遠(yuǎn)大于內(nèi)部距離時Matlab認(rèn)為按3類切會產(chǎn)生只有一兩個樣本的孤立簇于是自動減少類別數(shù)。這其實是算法的合理行為但容易讓不熟悉層次聚類的人誤以為代碼有bug。解決想要嚴(yán)格三類用clusterdata(X, 3)這種強(qiáng)制指定方式或者在譜系圖上找到三類對應(yīng)的兩個Cutoff高度直接按高度切。要明確一個邊界強(qiáng)制切出三類不代表結(jié)果有業(yè)務(wù)意義如果樹的頂層大類本身就該是兩類硬分成三類只是自欺欺人??醋V系圖判斷才是正路。5.5 別人打開.fig報缺函數(shù)現(xiàn)象把生成的dendrogram.fig發(fā)給同事對方Matlab沒有安裝統(tǒng)計與機(jī)器學(xué)習(xí)工具箱打開報錯或者圖形一片空白。原因fig文件保存的是圖形對象dendrogram生成的對象依賴工具箱的類定義缺工具箱時無法還原圖形。解決在運(yùn)行結(jié)束后額外導(dǎo)出通用圖片exportgraphics(gcf, result/dendrogram.png, Resolution, 300);PNG一張圖就能解決所有溝通問題。這也是我推薦把“導(dǎo)出PNG”寫進(jìn)工作流的原因圖比fig文件通用得多發(fā)到群里、貼進(jìn)報告、投到PPT里都無障礙。如果對方確實需要可編輯的圖再讓他裝工具箱或者把導(dǎo)出格式換成svg。5.6 linkage的single方法聚類結(jié)果像鏈條現(xiàn)象數(shù)據(jù)在中等數(shù)量下single方法生成的譜系圖像一個不斷連點(diǎn)的鏈條看不出明顯的簇狀結(jié)構(gòu)。原因single也就是最近鄰法只關(guān)注兩個簇之間最近的點(diǎn)容易被離群點(diǎn)“串”起來形成鏈?zhǔn)叫?yīng)。這在層次聚類的課本里專門有提到實際數(shù)據(jù)里幾乎一踩一個準(zhǔn)。解決換成ward或average。判斷哪個方法適合當(dāng)前數(shù)據(jù)可以對比不同方法的cophenet系數(shù)取最高者。需要注意cophenet系數(shù)也不是越高越好它衡量的是“樹”和“原始距離”的一致性但一致性高不等于簇之間有實際業(yè)務(wù)區(qū)分度最終還是要結(jié)合業(yè)務(wù)解釋來定。6. 二次開發(fā)方向把單次可視化腳本改造成可復(fù)用的聚類分析入口從拿到這份代碼到實際落地使用最值得做的改動就是把它從一個固定路徑的腳本改造成參數(shù)化入口。我建議先把main.m里所有讀路徑、聚類別數(shù)的硬編碼抽成函數(shù)入?yún)⒆兂深愃葡旅孢@樣一個接口function result run_hc_analysis(excel_path, sheet_name, varargin) % 輸入Excel路徑、sheet名可選參數(shù): Method, Cutoff, MaxClust p inputParser; addRequired(p, excel_path, ischar); addRequired(p, sheet_name, ischar); addParameter(p, Method, ward, ... (x) ismember(x, {ward, average, complete, single})); addParameter(p, MaxClust, [], isnumeric); parse(p, excel_path, sheet_name, varargin{:}); % 后續(xù)接原有聚類流程 end用inputParser做參數(shù)校驗是Matlab里比較工程化的寫法能為后續(xù)腳本批量化留出空間。改完之后我通常還會加一個export_report函數(shù)把每次跑的聚類方法、樣本數(shù)、cophenet系數(shù)和得到的簇數(shù)寫進(jìn)一張匯總表這樣多次調(diào)參的過程就有跡可循T table({excel_path}, k, c, num_groups, ... VariableNames, {DataSource, MaxClust, Cophenet, NumGroups}); writetable(T, result/run_log.xlsx, WriteMode, append);從那以后我每次拿一份新數(shù)據(jù)跑聚類都強(qiáng)制走一遍這個入口先讀數(shù)據(jù)看一眼列名再跑默認(rèn)參數(shù)最后對著譜系圖的斷層高度微調(diào)Cutoff。整個流程從五分鐘壓縮到兩分鐘而且每次跑的參數(shù)和結(jié)果都留在日志里回溯問題時再也不用靠腦子記。這個改造本身不復(fù)雜但把“一次性腳本”變成“可復(fù)用工具”的體驗確實值得你花半小時做一次。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取