實(shí)戰(zhàn):從數(shù)據(jù)準(zhǔn)備到結(jié)果驗(yàn)證的完整指南)
簡(jiǎn)介這份資源是面向本科及以上學(xué)習(xí)者、科研人員與工程實(shí)踐者的MATLAB聚類(lèi)分析工具包圍繞k-means算法解決數(shù)據(jù)分組與模式識(shí)別問(wèn)題適合課程作業(yè)、論文實(shí)驗(yàn)及項(xiàng)目原型開(kāi)發(fā)等場(chǎng)景。壓縮包共10個(gè)文件約378KB包含2個(gè).m主程序腳本、1個(gè).xls與1個(gè).xlsx數(shù)據(jù)表格以及6張jpg結(jié)果示意圖代碼完整且附有注釋數(shù)據(jù)齊全便于直接運(yùn)行與后續(xù)擴(kuò)展。資源已有232人學(xué)習(xí)下載說(shuō)明其在教學(xué)與實(shí)踐中具有一定參考價(jià)值。讀者可獲得一套可復(fù)用的k-means實(shí)現(xiàn)流程包括數(shù)據(jù)讀取、聚類(lèi)計(jì)算與結(jié)果可視化配合示例數(shù)據(jù)與運(yùn)行截圖能快速理解算法參數(shù)設(shè)置與效果評(píng)估并在此基礎(chǔ)上修改距離度量、聚類(lèi)數(shù)目或替換數(shù)據(jù)集完成創(chuàng)新性擴(kuò)展。若運(yùn)行中遇到疑問(wèn)也可聯(lián)系作者獲取支持。1. 從一份能跑的 kmeans 聚類(lèi) MATLAB 代碼說(shuō)起數(shù)據(jù)齊全到底意味著什么很多人第一次接觸聚類(lèi)是在一堆沒(méi)有標(biāo)簽的樣本面前發(fā)懵分類(lèi)模型用不了因?yàn)闆](méi)人告訴你哪條數(shù)據(jù)屬于哪一類(lèi)。kmeans 聚類(lèi)分析就是干這個(gè)的——它不需要標(biāo)簽只靠樣本之間的距離把相似的東西自動(dòng)歸堆。MATLAB 做這件事有天然優(yōu)勢(shì)矩陣運(yùn)算快、可視化順手、統(tǒng)計(jì)與機(jī)器學(xué)習(xí)工具箱里現(xiàn)成的函數(shù)拿來(lái)就能用。但真正卡住新手的往往不是算法本身而是「代碼完整、數(shù)據(jù)齊全」這六個(gè)字背后的東西數(shù)據(jù)長(zhǎng)什么樣、維度怎么統(tǒng)一、聚類(lèi)數(shù) K 怎么定、結(jié)果怎么驗(yàn)證。這篇筆記就圍繞一份可直接復(fù)現(xiàn)的 kmeans 聚類(lèi) MATLAB 代碼把數(shù)據(jù)準(zhǔn)備、參數(shù)設(shè)置、結(jié)果評(píng)估和踩坑記錄一次講透適合剛上手聚類(lèi)、手里有數(shù)據(jù)但不知道怎么落地的人。2. kmeans 在 MATLAB 里到底怎么算原理、選型與最小可跑代碼2.1 算法核心與 MATLAB 的實(shí)現(xiàn)路徑kmeans 的目標(biāo)很樸素把 N 個(gè)樣本分成 K 個(gè)簇讓每個(gè)樣本到它所屬簇中心的距離平方和最小。數(shù)學(xué)上就是最小化簇內(nèi)平方誤差和這個(gè)目標(biāo)函數(shù)沒(méi)有解析解所以用迭代逼近。標(biāo)準(zhǔn)流程是四步初始化 K 個(gè)中心、把每個(gè)樣本分配給最近的中心、重新計(jì)算每個(gè)簇的中心、重復(fù)分配和更新直到中心不再明顯移動(dòng)或達(dá)到迭代上限。MATLAB 里實(shí)現(xiàn) kmeans 有兩條路。一條是統(tǒng)計(jì)與機(jī)器學(xué)習(xí)工具箱的kmeans函數(shù)一行調(diào)用就能出結(jié)果支持距離度量、重復(fù)次數(shù)、并行等參數(shù)另一條是自己寫(xiě)循環(huán)適合理解算法細(xì)節(jié)或做教學(xué)演示。實(shí)際項(xiàng)目里我一般先用內(nèi)置函數(shù)跑通基線(xiàn)確認(rèn)數(shù)據(jù)沒(méi)問(wèn)題、K 值合理再考慮要不要手寫(xiě)改造。內(nèi)置函數(shù)底層用的是 Lloyd 算法配合 kmeans 初始化能顯著降低陷入局部最優(yōu)的概率。選型上要注意如果你的數(shù)據(jù)維度很高比如上百維歐氏距離會(huì)失效這時(shí)候要么先降維PCA、t-SNE要么換余弦距離。如果簇的形狀不是球形kmeans 本身就不合適得考慮 DBSCAN 或譜聚類(lèi)。這些邊界在動(dòng)手前就要想清楚否則跑出來(lái)的結(jié)果看著有模有樣實(shí)際沒(méi)法用。2.2 數(shù)據(jù)準(zhǔn)備從原始表格到聚類(lèi)矩陣「數(shù)據(jù)齊全」不是指文件多而是指數(shù)據(jù)能直接喂進(jìn)算法。kmeans 要求輸入是一個(gè) N×D 的數(shù)值矩陣每行一個(gè)樣本每列一個(gè)特征。常見(jiàn)的數(shù)據(jù)問(wèn)題有三類(lèi)缺失值、量綱不統(tǒng)一、類(lèi)別型字段沒(méi)編碼。缺失值處理上我一般先看缺失比例。低于 5% 的用列均值或中位數(shù)填補(bǔ)高于 20% 的考慮直接刪列或換特征。量綱問(wèn)題更隱蔽比如一個(gè)特征是年齡0-100另一個(gè)是年收入0-1000000不標(biāo)準(zhǔn)化的話(huà)收入會(huì)完全主導(dǎo)距離計(jì)算年齡等于白給。標(biāo)準(zhǔn)做法是 z-score 標(biāo)準(zhǔn)化讓每個(gè)特征均值為 0、標(biāo)準(zhǔn)差為 1。下面是一段數(shù)據(jù)準(zhǔn)備代碼假設(shè)原始數(shù)據(jù)存在 Excel 里包含數(shù)值列和幾個(gè)類(lèi)別列% 讀取原始數(shù)據(jù)第一行為表頭 rawData readtable(raw_data.xlsx); % 查看前幾行確認(rèn)列名和數(shù)據(jù)類(lèi)型 head(rawData); % 分離數(shù)值特征和類(lèi)別特征 numFeatures rawData(:, {Age, Income, Score, Spend}); catFeatures rawData(:, {Gender, City}); % 類(lèi)別特征做獨(dú)熱編碼轉(zhuǎn)成數(shù)值 catEncoded onehotencode(catFeatures, 1:width(catFeatures)); % 合并成完整特征矩陣 featureMatrix [table2array(numFeatures), catEncoded]; % 缺失值用列中位數(shù)填補(bǔ) featureMatrix fillmissing(featureMatrix, constant, ... median(featureMatrix, 1, omitnan)); % z-score 標(biāo)準(zhǔn)化每列減均值除標(biāo)準(zhǔn)差 featureMatrix zscore(featureMatrix); % 確認(rèn)最終矩陣尺寸 fprintf(樣本數(shù): %d, 特征數(shù): %d\n, size(featureMatrix, 1), size(featureMatrix, 2));這段代碼的邏輯是先讀表把數(shù)值列和類(lèi)別列分開(kāi)處理類(lèi)別列用獨(dú)熱編碼變成 0/1 向量再拼回一個(gè)大矩陣。fillmissing用列中位數(shù)填補(bǔ)比均值更抗異常值。zscore是標(biāo)準(zhǔn)化關(guān)鍵少了這一步后面聚類(lèi)結(jié)果基本不可信。參數(shù)上onehotencode的第二個(gè)參數(shù)指定對(duì)哪些列編碼fillmissing的constant配合中位數(shù)是常見(jiàn)組合。跑完看輸出尺寸如果特征數(shù)和你預(yù)期對(duì)不上多半是獨(dú)熱編碼把某一列拆成了多列。2.3 最小可跑的 kmeans 調(diào)用與參數(shù)含義數(shù)據(jù)準(zhǔn)備好之后核心調(diào)用就一行。但這一行里的參數(shù)決定了結(jié)果好壞不能隨便填% 設(shè)定聚類(lèi)數(shù) K先用肘部法粗定一個(gè)范圍 K 4; % 調(diào)用 kmeans關(guān)鍵參數(shù)逐個(gè)說(shuō)明 [idx, C, sumd, D] kmeans(featureMatrix, K, ... Distance, sqeuclidean, ... % 距離度量默認(rèn)平方歐氏 Replicates, 10, ... % 重復(fù) 10 次取最優(yōu)降低局部最優(yōu)風(fēng)險(xiǎn) Start, plus, ... % kmeans 初始化 MaxIter, 500, ... % 單次迭代上限 Display, final); % 只輸出最終結(jié)果避免刷屏 % idx 是每個(gè)樣本的簇編號(hào)C 是 K 個(gè)簇中心sumd 是簇內(nèi)距離和 fprintf(各簇樣本數(shù): ); disp(histcounts(idx, 1:K1));idx是 N×1 的簇標(biāo)簽C是 K×D 的中心矩陣sumd是每個(gè)簇內(nèi)樣本到中心的距離平方和D是每個(gè)樣本到所有中心的距離。Replicates設(shè) 10 是經(jīng)驗(yàn)值數(shù)據(jù)量大或 K 大時(shí)可以加到 20代價(jià)是時(shí)間線(xiàn)性增長(zhǎng)。Start用plus就是 kmeans比默認(rèn)的均勻采樣穩(wěn)。MaxIter一般 300 到 500 夠用設(shè)太小可能沒(méi)收斂就停了。跑完用histcounts看各簇樣本數(shù)如果某一簇只有個(gè)位數(shù)樣本要么是 K 設(shè)大了要么是數(shù)據(jù)里有離群點(diǎn)。3. 聚類(lèi)數(shù) K 怎么定肘部法、輪廓系數(shù)與業(yè)務(wù)約束的三方博弈3.1 肘部法的計(jì)算與讀圖K 是 kmeans 唯一需要人為指定的關(guān)鍵參數(shù)也是最容易拍腦袋的地方。肘部法的思路是隨著 K 增大簇內(nèi)距離和必然下降但下降速度會(huì)在某個(gè)點(diǎn)明顯變緩那個(gè)拐點(diǎn)就是候選 K。實(shí)現(xiàn)上就是循環(huán)跑不同 K記錄sumd總和% 測(cè)試 K 從 1 到 10 的簇內(nèi)距離和 K_range 1:10; wss zeros(length(K_range), 1); for i 1:length(K_range) [~, ~, sumd] kmeans(featureMatrix, K_range(i), ... Replicates, 5, Start, plus, Display, off); wss(i) sum(sumd); end % 畫(huà)肘部圖 figure; plot(K_range, wss, -o, LineWidth, 1.5); xlabel(聚類(lèi)數(shù) K); ylabel(簇內(nèi)距離和); title(肘部法確定 K); grid on; % 計(jì)算相鄰點(diǎn)的下降率輔助判斷拐點(diǎn) dropRate -diff(wss) ./ wss(1:end-1); disp(table(K_range(2:end), dropRate, VariableNames, {K, DropRate}));wss是 within-cluster sum of squares隨 K 單調(diào)下降??磮D時(shí)找下降率突然變小的位置比如從 K3 到 4 降了 30%從 4 到 5 只降了 8%那 4 就是候選。代碼里額外算了dropRate比肉眼讀圖更客觀。注意Replicates這里設(shè) 5 就夠因?yàn)橹皇潜容^趨勢(shì)不需要每個(gè) K 都跑到最優(yōu)。3.2 輪廓系數(shù)比肘部法更硬的指標(biāo)肘部法主觀性強(qiáng)輪廓系數(shù)silhouette能給出每個(gè)樣本的聚類(lèi)質(zhì)量分?jǐn)?shù)范圍 -1 到 1越接近 1 說(shuō)明樣本離本簇近、離其他簇遠(yuǎn)。MATLAB 里silhouette函數(shù)直接算% 對(duì)候選 K 計(jì)算平均輪廓系數(shù) K_candidates 2:8; silScores zeros(length(K_candidates), 1); for i 1:length(K_candidates) idx kmeans(featureMatrix, K_candidates(i), ... Replicates, 10, Start, plus, Display, off); silScores(i) mean(silhouette(featureMatrix, idx)); end % 輸出對(duì)比表 disp(table(K_candidates, silScores, VariableNames, {K, Silhouette})); % 找最高分對(duì)應(yīng)的 K [bestScore, bestIdx] max(silScores); fprintf(最佳 K %d, 輪廓系數(shù) %.4f\n, K_candidates(bestIdx), bestScore);輪廓系數(shù)對(duì)距離度量敏感如果前面沒(méi)做標(biāo)準(zhǔn)化這里分?jǐn)?shù)會(huì)普遍偏低且不可比。一般平均輪廓系數(shù)高于 0.5 算結(jié)構(gòu)清晰0.3 到 0.5 算可接受低于 0.25 就要懷疑數(shù)據(jù)本身沒(méi)有明顯簇結(jié)構(gòu)。注意輪廓系數(shù)在 K2 時(shí)往往偏高這是它的已知偏向所以不能只看分?jǐn)?shù)要結(jié)合肘部法和業(yè)務(wù)含義。3.3 業(yè)務(wù)約束下的 K 選擇純數(shù)學(xué)指標(biāo)給的是候選最終定 K 還要看業(yè)務(wù)能不能用。比如做用戶(hù)分群分成 3 群和 5 群對(duì)應(yīng)的運(yùn)營(yíng)策略完全不同5 群可能細(xì)到?jīng)]法針對(duì)性投放。我一般會(huì)做一張對(duì)照表把不同 K 下的簇大小、中心特征、輪廓系數(shù)列出來(lái)和業(yè)務(wù)方一起過(guò)一遍。如果某個(gè) K 下出現(xiàn)一個(gè)超大簇加幾個(gè)極小簇通常說(shuō)明 K 偏大或者數(shù)據(jù)里有離群點(diǎn)沒(méi)處理。這一步?jīng)]有代碼能替代但前面算出的C和idx就是討論的素材。4. 結(jié)果可視化與簇特征解讀讓聚類(lèi)結(jié)果能講出人話(huà)4.1 二維和三維散點(diǎn)圖的畫(huà)法聚類(lèi)結(jié)果如果只給一堆標(biāo)簽沒(méi)人看得懂。可視化是讓結(jié)果落地的關(guān)鍵一步。高維數(shù)據(jù)沒(méi)法直接畫(huà)常規(guī)做法是先用 PCA 降到 2 維或 3 維再按簇標(biāo)簽上色% PCA 降到二維用于可視化 [coeff, score, ~, ~, explained] pca(featureMatrix); score2d score(:, 1:2); % 按簇標(biāo)簽畫(huà)散點(diǎn)圖 figure; gscatter(score2d(:,1), score2d(:,2), idx, lines(K), ., 12); xlabel(sprintf(PC1 (%.1f%%), explained(1))); ylabel(sprintf(PC2 (%.1f%%), explained(2))); title(kmeans 聚類(lèi)結(jié)果PCA 二維投影); grid on; % 疊加簇中心在 PCA 空間的投影 hold on; center2d (C - mean(featureMatrix)) * coeff(:, 1:2); plot(center2d(:,1), center2d(:,2), kx, MarkerSize, 14, LineWidth, 2); hold off;gscatter按idx分組上色比手動(dòng)循環(huán)scatter省事。explained告訴你前兩個(gè)主成分解釋了多少方差如果加起來(lái)不到 50%說(shuō)明二維投影丟失信息太多圖只能當(dāng)參考不能下結(jié)論。中心點(diǎn)投影那一步是把原始空間的C通過(guò)同樣的均值和coeff變換到 PCA 空間這樣中心點(diǎn)和樣本點(diǎn)在同一坐標(biāo)系里方便看簇的緊致程度。4.2 簇中心反標(biāo)準(zhǔn)化與特征畫(huà)像PCA 圖看的是整體分布要解釋每個(gè)簇是什么得回到原始特征空間看中心。但前面做了 z-score中心值是標(biāo)準(zhǔn)化的得反變換回去% 保存標(biāo)準(zhǔn)化參數(shù)在 zscore 那一步之后 mu mean(featureMatrix_raw, 1); sigma std(featureMatrix_raw, 0, 1); % 反標(biāo)準(zhǔn)化簇中心 C_original C .* sigma mu; % 把中心轉(zhuǎn)成表格方便對(duì)照列名 centerTable array2table(C_original, ... VariableNames, featureMatrix_colnames); disp(centerTable); % 對(duì)每個(gè)簇找出中心值最高的三個(gè)特征 for k 1:K [~, topIdx] maxk(C_original(k,:), 3); fprintf(簇 %d 主導(dǎo)特征: %s\n, k, strjoin(featureMatrix_colnames(topIdx), , )); end這里的關(guān)鍵是mu和sigma必須在標(biāo)準(zhǔn)化之前從原始矩陣算出來(lái)并保存否則反變換對(duì)不上。C_original的每一行是一個(gè)簇在原始量綱下的中心比如年齡 35、收入 8000 這樣業(yè)務(wù)方一看就懂。maxk找每個(gè)簇最突出的特征快速生成畫(huà)像描述。如果某個(gè)簇在多個(gè)特征上都偏高說(shuō)明這個(gè)簇的特征不單一可能需要拆或者合并。4.3 用輪廓圖定位問(wèn)題樣本整體輪廓系數(shù)是平均值掩蓋了個(gè)體差異。輪廓圖能把每個(gè)樣本的分?jǐn)?shù)畫(huà)出來(lái)一眼看出哪些樣本分錯(cuò)了figure; [silVals, ~] silhouette(featureMatrix, idx, sqeuclidean); title(各樣本輪廓系數(shù)); % 找出輪廓系數(shù)為負(fù)的樣本這些是可能分錯(cuò)的 negIdx find(silVals 0); fprintf(輪廓系數(shù)為負(fù)的樣本數(shù): %d (占比 %.1f%%)\n, ... length(negIdx), 100*length(negIdx)/length(silVals)); % 輸出這些樣本的原始索引和當(dāng)前簇標(biāo)簽 if ~isempty(negIdx) disp(table(negIdx, idx(negIdx), silVals(negIdx), ... VariableNames, {SampleIndex, Cluster, Silhouette})); end輪廓系數(shù)為負(fù)意味著樣本到其他簇的平均距離比到本簇還近基本可以判定分錯(cuò)了。占比低于 5% 可以接受高于 10% 就要回頭檢查 K 是否合理、特征是否夠區(qū)分。這些負(fù)分樣本往往是邊界情況業(yè)務(wù)上可能正好是需要單獨(dú)關(guān)注的那批人。5. 避坑與排查kmeans 聚類(lèi) MATLAB 實(shí)現(xiàn)里最容易翻車(chē)的五件事5.1 沒(méi)標(biāo)準(zhǔn)化導(dǎo)致某列特征獨(dú)大現(xiàn)象聚類(lèi)結(jié)果里某一簇的樣本在某個(gè)特征上高度一致其他特征完全隨機(jī)看起來(lái)像按單一維度分的。原因不同特征量綱差異大距離計(jì)算被大量綱特征主導(dǎo)。解決聚類(lèi)前對(duì)所有數(shù)值特征做 z-score 或 min-max 標(biāo)準(zhǔn)化并在反標(biāo)準(zhǔn)化解讀中心時(shí)用對(duì)應(yīng)的均值和標(biāo)準(zhǔn)差還原。判斷方法很簡(jiǎn)單看簇中心表里各特征的數(shù)值范圍如果某一列數(shù)值比其他列大幾個(gè)數(shù)量級(jí)基本就是這個(gè)問(wèn)題。5.2 K 值拍腦袋定結(jié)果沒(méi)法解釋現(xiàn)象跑出來(lái)的簇大小嚴(yán)重不均或者業(yè)務(wù)方問(wèn)「為什么是 4 類(lèi)不是 3 類(lèi)」時(shí)答不上來(lái)。原因只跑了一次 kmeans沒(méi)做 K 的掃描和對(duì)比。解決至少用肘部法和輪廓系數(shù)各掃一遍 K 的范圍把不同 K 下的簇大小、輪廓系數(shù)、中心特征列成表選數(shù)學(xué)指標(biāo)和業(yè)務(wù)含義都說(shuō)得通的那個(gè)。我一般會(huì)把 2 到 8 的結(jié)果都留著業(yè)務(wù)討論時(shí)隨時(shí)調(diào)出來(lái)看。5.3 忽略 Replicates 導(dǎo)致結(jié)果每次不一樣現(xiàn)象同樣的數(shù)據(jù)和 K兩次運(yùn)行得到的簇標(biāo)簽和中心不同。原因kmeans 對(duì)初始中心敏感單次運(yùn)行容易陷入局部最優(yōu)。解決Replicates設(shè) 10 以上Start用plus。如果數(shù)據(jù)量特別大導(dǎo)致重復(fù)太慢可以先用sample初始化跑一次看大概再用plus加Replicates精跑。另外注意即使這樣簇的編號(hào)也可能不同比較兩次結(jié)果時(shí)要看中心而不是看標(biāo)簽數(shù)字。5.4 缺失值沒(méi)處理直接進(jìn) kmeans現(xiàn)象代碼報(bào)錯(cuò)NaN相關(guān)或者結(jié)果里某些樣本的簇標(biāo)簽異常。原因kmeans不接受含 NaN 的輸入矩陣。解決進(jìn) kmeans 之前必須fillmissing或rmmissing。填補(bǔ)方法上數(shù)值列用中位數(shù)比均值穩(wěn)類(lèi)別列用眾數(shù)。如果某列缺失超過(guò) 30%我傾向于直接刪掉這列因?yàn)樘钛a(bǔ)引入的偏差可能比丟掉這列更大。5.5 把聚類(lèi)結(jié)果當(dāng)分類(lèi)標(biāo)簽用現(xiàn)象拿 kmeans 的idx去訓(xùn)練一個(gè)分類(lèi)器然后在新數(shù)據(jù)上預(yù)測(cè)發(fā)現(xiàn)效果很差。原因kmeans 給出的簇編號(hào)沒(méi)有跨數(shù)據(jù)集的一致性新數(shù)據(jù)跑一遍 kmeans 得到的編號(hào)和舊數(shù)據(jù)對(duì)不上。解決如果要做預(yù)測(cè)應(yīng)該用聚類(lèi)中心訓(xùn)練一個(gè)分類(lèi)器比如最近鄰或 SVM把中心作為「?jìng)螛?biāo)簽」的來(lái)源而不是直接用編號(hào)?;蛘哂胟nnsearch把新樣本分配到最近的已有中心。這個(gè)坑很隱蔽因?yàn)樵谧约簲?shù)據(jù)集上驗(yàn)證時(shí)看著沒(méi)問(wèn)題一上生產(chǎn)就露餡。6. 從能跑到好用kmeans 結(jié)果穩(wěn)定性驗(yàn)證與增量分配的一個(gè)實(shí)用技巧代碼能跑通只是起點(diǎn)真正投入使用前我會(huì)做一件事驗(yàn)證聚類(lèi)結(jié)果的穩(wěn)定性。方法不復(fù)雜把數(shù)據(jù)隨機(jī)分成兩半各自跑 kmeans然后比較兩半得到的簇中心是否接近。如果中心差異很大說(shuō)明數(shù)據(jù)本身沒(méi)有穩(wěn)定結(jié)構(gòu)或者 K 選得不對(duì)。MATLAB 里可以用pdist2算兩組中心的距離矩陣看最小距離是否在可接受范圍內(nèi)。% 隨機(jī)對(duì)半切分 n size(featureMatrix, 1); halfIdx randperm(n, floor(n/2)); dataA featureMatrix(halfIdx, :); dataB featureMatrix(setdiff(1:n, halfIdx), :); % 各自跑 kmeans K 4; [~, CA] kmeans(dataA, K, Replicates, 10, Start, plus, Display, off); [~, CB] kmeans(dataB, K, Replicates, 10, Start, plus, Display, off); % 計(jì)算兩組中心的兩兩距離 centerDist pdist2(CA, CB); minDist min(centerDist, [], 2); fprintf(各中心到另一組最近中心的距離: ); disp(minDist); % 如果每個(gè)中心都能在另一組找到距離小于閾值的對(duì)應(yīng)中心認(rèn)為穩(wěn)定 threshold 0.5; % 標(biāo)準(zhǔn)化空間下的經(jīng)驗(yàn)閾值 stable all(minDist threshold); fprintf(聚類(lèi)結(jié)果穩(wěn)定: %s\n, string(stable));這段代碼的核心是pdist2算兩組中心的距離矩陣minDist是每個(gè) A 組中心到 B 組最近中心的距離。閾值 0.5 是在標(biāo)準(zhǔn)化空間下的經(jīng)驗(yàn)值因?yàn)闃?biāo)準(zhǔn)化后特征標(biāo)準(zhǔn)差為 1中心距離小于半個(gè)標(biāo)準(zhǔn)差算接近。如果某個(gè)中心的最小距離超過(guò) 1說(shuō)明這一簇在兩半數(shù)據(jù)里位置差異大要么是樣本太少不穩(wěn)定要么是 K 偏大。另一個(gè)實(shí)用技巧是增量分配當(dāng)有新樣本進(jìn)來(lái)時(shí)不需要重新跑整個(gè) kmeans直接用已有的中心做最近鄰分配。knnsearch或者手動(dòng)算距離都行% 新樣本標(biāo)準(zhǔn)化用訓(xùn)練時(shí)的 mu 和 sigma newSample (newRaw - mu) ./ sigma; % 分配到最近的中心 [d, assignedCluster] min(pdist2(newSample, C), [], 2); fprintf(新樣本分配到簇 %d距離 %.4f\n, assignedCluster, d);這樣做的前提是新樣本的分布和訓(xùn)練數(shù)據(jù)一致如果業(yè)務(wù)發(fā)生突變比如用戶(hù)行為模式整體偏移增量分配會(huì)失效這時(shí)候需要重新聚類(lèi)。我一般會(huì)監(jiān)控新樣本到最近中心的平均距離如果持續(xù)上升就是重新訓(xùn)練的觸發(fā)信號(hào)。這套流程跑下來(lái)從數(shù)據(jù)準(zhǔn)備到結(jié)果驗(yàn)證大概兩三百行代碼覆蓋了 kmeans 聚類(lèi)分析在 MATLAB 里落地的完整鏈路。我自己踩過(guò)最深的坑是早期不做標(biāo)準(zhǔn)化直接跑結(jié)果對(duì)著簇中心表看了半天沒(méi)看出規(guī)律后來(lái)才發(fā)現(xiàn)是收入那一列把距離全吃掉了。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取