操指南:從數(shù)據(jù)導(dǎo)入到模型部署)
簡(jiǎn)介圍繞MATLAB統(tǒng)計(jì)與機(jī)器學(xué)習(xí)工具箱Statistics and Machine Learning Toolbox編寫的使用說(shuō)明與案例文檔面向需要進(jìn)行統(tǒng)計(jì)分析、回歸建模和聚類分析的工程師、科研人員及本科生。文檔先概述該工具箱在描述統(tǒng)計(jì)、假設(shè)檢驗(yàn)、方差分析、回歸、分類、聚類和數(shù)據(jù)預(yù)處理等方面的功能再介紹mean、std、ttest、fitlm、kmeans等常用函數(shù)幫助已經(jīng)掌握MATLAB基礎(chǔ)操作的用戶快速進(jìn)入數(shù)據(jù)建模環(huán)節(jié)。文檔結(jié)構(gòu)從工具箱概述、功能清單、常用函數(shù)說(shuō)明到案例實(shí)踐逐步展開兩個(gè)案例分別演示線性回歸和K均值聚類包含數(shù)據(jù)準(zhǔn)備、模型建立、結(jié)果可視化等完整步驟便于讀者對(duì)照練習(xí)并理解從數(shù)據(jù)到模型的完整思路。資源包共1個(gè)文件為doc格式約33KB內(nèi)容集中適合查閱和打印。該文檔已有1400余人瀏覽學(xué)習(xí)對(duì)于希望系統(tǒng)掌握MATLAB統(tǒng)計(jì)與機(jī)器學(xué)習(xí)方法、并能直接用于實(shí)際數(shù)據(jù)任務(wù)的讀者來(lái)說(shuō)具有較強(qiáng)參考價(jià)值。1. 為什么 Statistics and Machine Learning Toolbox 值得單獨(dú)學(xué)它把建模從“玄學(xué)”變成“流水線”剛接觸 MATLAB 的人多半是從矩陣運(yùn)算、Simulink 或者圖像處理入的門等到手里攢了一批實(shí)驗(yàn)數(shù)據(jù)、想跑個(gè)分類或者回歸的時(shí)候才發(fā)現(xiàn) MATLAB 的機(jī)器學(xué)習(xí)能力和 Python 的 scikit-learn 是兩種完全不同的體驗(yàn)。Statistics and Machine Learning Toolbox 不是一套零散的算法集合它把“數(shù)據(jù)導(dǎo)入 → 預(yù)處理 → 特征工程 → 模型訓(xùn)練 → 驗(yàn)證評(píng)估 → 部署”這條鏈路做成了統(tǒng)一的函數(shù)接口你不需要自己拼湊十幾個(gè)第三方包也不需要在不同數(shù)據(jù)結(jié)構(gòu)之間來(lái)回轉(zhuǎn)換。對(duì)于已經(jīng)裝了 matlab 2023b 或更新版本的人來(lái)說(shuō)這個(gè)工具箱是自帶的一部分它解決的是“我有一份 Excel 表怎么在半小時(shí)內(nèi)得到一個(gè)能交代結(jié)論的模型”這個(gè)實(shí)際訴求。這篇筆記我從一線使用的角度把這個(gè)工具箱拆成四條主線能做什么、怎么組織數(shù)據(jù)、模型怎么選、參數(shù)怎么調(diào)、哪些地方最容易翻車。適合手里有數(shù)據(jù)但沒系統(tǒng)學(xué)過(guò)機(jī)器學(xué)習(xí)的人也適合被 Python 生態(tài)折騰過(guò)、想回到 MATLAB 里快速驗(yàn)證想法的工程師。后面所有代碼都基于我慣用的 2023b 版本低版本R2021a 之前部分函數(shù)名不同我會(huì)在對(duì)應(yīng)位置標(biāo)注差異。2. 從原始表格到第一個(gè)模型fit 系列函數(shù)的最小可用流程2.1 數(shù)據(jù)進(jìn) MATLAB 的正確姿勢(shì)tables 是工具箱的第一公民這個(gè)工具箱里幾乎所有模型函數(shù)都接受 table 類型作為輸入而不是傳統(tǒng)的 double 矩陣。這一點(diǎn)和很多 MATLAB 老手的直覺相反——用慣了xlsread或者load的人習(xí)慣拿到數(shù)據(jù)先double()轉(zhuǎn)矩陣但在 Statistics and Machine Learning Toolbox 里table 能幫你自動(dòng)記住變量名預(yù)測(cè)結(jié)果、特征重要性、混淆矩陣全部按變量名輸出省掉大量索引對(duì)位的痛苦。第一步永遠(yuǎn)是導(dǎo)入數(shù)據(jù)。readtable是最常用的入口它可以直接讀 CSV、Excel、TXT甚至帶分隔符的日志文件% 導(dǎo)入一份分類任務(wù)數(shù)據(jù)特征列 標(biāo)簽列 data readtable(sample_data.csv, TextType, string); disp(data.Properties.VariableNames); % 查看變量名 disp(height(data)); % 看看有多少行這里的TextType參數(shù)決定文本列被讀成 string 還是 cell。默認(rèn)char會(huì)在后續(xù)建模時(shí)產(chǎn)生一些小麻煩建議統(tǒng)一設(shè)置成string。讀完后順手做一次缺失值檢查用ismissing行數(shù)太少的數(shù)據(jù)直接放棄不要硬建模。我一般會(huì)在讀入后 30 秒內(nèi)跑完這兩行先判斷數(shù)據(jù)能不能用再?zèng)Q定要不要繼續(xù)做特征工程。2.2 fit 之前必須做的兩件事劃分訓(xùn)練集和特征標(biāo)準(zhǔn)化工具箱里的cvpartition是劃分?jǐn)?shù)據(jù)最穩(wěn)的函數(shù)比手動(dòng)randperm好在能保證分層抽樣——分類問題里每個(gè)類別的樣本比例在訓(xùn)練集和測(cè)試集中保持一致這個(gè)細(xì)節(jié)直接決定小樣本數(shù)據(jù)集上的評(píng)估結(jié)果是否可信。% 按 7:3 劃分訓(xùn)練/測(cè)試保持類別比例分層抽樣 rng(42); % 固定隨機(jī)種子確保結(jié)果可復(fù)現(xiàn) cv cvpartition(data.label, HoldOut, 0.3); trainIdx training(cv); testIdx test(cv); % 特征標(biāo)準(zhǔn)化用訓(xùn)練集的均值和標(biāo)準(zhǔn)差去轉(zhuǎn)換測(cè)試集避免數(shù)據(jù)泄漏 X_train data{trainIdx, 1:end-1}; X_test data{testIdx, 1:end-1}; y_train data.label(trainIdx); y_test data.label(testIdx); % 標(biāo)準(zhǔn)化 mu mean(X_train); sigma std(X_train); X_train_std (X_train - mu) ./ sigma; X_test_std (X_test - mu) ./ sigma;這里有個(gè)新手必踩的坑標(biāo)準(zhǔn)化時(shí)必須只算訓(xùn)練集的均值和標(biāo)準(zhǔn)差然后拿這套參數(shù)去變換測(cè)試集。如果先對(duì)全量數(shù)據(jù)標(biāo)準(zhǔn)化再劃分測(cè)試集的信息就“泄漏”到了訓(xùn)練過(guò)程里驗(yàn)證精度會(huì)虛高 38 個(gè)百分點(diǎn)等模型上線后立刻現(xiàn)原形。cvpartition的HoldOut參數(shù)取 0.3 表示留 30% 做測(cè)試數(shù)值越大測(cè)試集越大但訓(xùn)練數(shù)據(jù)會(huì)變少具體比例根據(jù)你的樣本量酌情調(diào)整樣本量小于 500 時(shí)建議改用KFold, 5做五折交叉驗(yàn)證而不是一次性留出 30%。2.3 跑一個(gè)最小分類模型fitcknn 三行出結(jié)果KNNK 近鄰在工具箱里的入口是fitcknn它不需要訓(xùn)練過(guò)程本質(zhì)上是把訓(xùn)練數(shù)據(jù)存下來(lái)、預(yù)測(cè)時(shí)算距離。雖然它簡(jiǎn)單到不像機(jī)器學(xué)習(xí)但它能幫你在 5 分鐘內(nèi)驗(yàn)證“數(shù)據(jù)里到底有沒有信號(hào)”——如果 KNN 在測(cè)試集上準(zhǔn)確率都不到 60%后面的復(fù)雜模型大概率也救不回來(lái)。% 訓(xùn)練一個(gè) KNN 分類器 mdl_knn fitcknn(X_train_std, y_train, ... NumNeighbors, 5, ... Distance, euclidean, ... Standardize, false); % 已手動(dòng)標(biāo)準(zhǔn)化這里關(guān)閉 % 預(yù)測(cè)并評(píng)估 y_pred_knn predict(mdl_knn, X_test_std); accuracy_knn sum(y_pred_knn y_test) / numel(y_test); fprintf(KNN 準(zhǔn)確率: %.2f%%\n, accuracy_knn * 100); % 混淆矩陣可視化分類細(xì)節(jié) confusionchart(y_test, y_pred_knn);NumNeighbors控制 K 值K 越小決策邊界越復(fù)雜越容易過(guò)擬合K 越大越平滑但會(huì)丟失局部模式。Distance選euclidean是連續(xù)特征場(chǎng)景下的默認(rèn)做法如果特征里混有 0/1 二值變量可以試試hamming。fitcknn在 R2021b 之后支持Standardize參數(shù)但如果你已經(jīng)手動(dòng)標(biāo)準(zhǔn)化了這里必須寫成false否則會(huì)二次標(biāo)準(zhǔn)化導(dǎo)致特征尺度被破壞。這個(gè)最小流程跑通后整套工具箱的使用邏輯就通了——fitc開頭的函數(shù)管分類fitr開頭的函數(shù)管回歸預(yù)測(cè)統(tǒng)一用predict評(píng)估統(tǒng)一用損失函數(shù)或手工計(jì)算指標(biāo)。3. 分類、回歸、聚類三大任務(wù)下工具箱的算法選型與參數(shù)必調(diào)項(xiàng)3.1 分類任務(wù)從判別分析到集成學(xué)習(xí)工具箱里到底該選誰(shuí)工具箱里的分類器大致分四代第一代是判別分析fitcdiscr適合線性可分且特征維度不高的情況第二代是 KNN 和樸素貝葉斯適合快速基準(zhǔn)第三代是 SVMfitcecoc或fitcsvm和決策樹適合非線性邊界第四代是集成學(xué)習(xí)fitcensemble是當(dāng)前默認(rèn)推薦項(xiàng)因?yàn)樗茏詣?dòng)組合大量弱學(xué)習(xí)器并達(dá)到比單模型更穩(wěn)的效果。我一般會(huì)先跑fitcensemble和fitcecoc做對(duì)比因?yàn)檫@兩個(gè)模型覆蓋了“裝袋/提升”和“核映射”兩條最主流的路線% 集成學(xué)習(xí)100 棵決策樹AdaBoostM2 提升 mdl_ens fitcensemble(X_train_std, y_train, ... Method, AdaBoostM2, ... NumLearningCycles, 100, ... Learners, tree); % 多分類 SVM一對(duì)多策略RBF 核 mdl_svm fitcecoc(X_train_std, y_train, ... Learners, templateSVM(KernelFunction, rbf, ... BoxConstraint, 1, KernelScale, auto)); % 對(duì)比測(cè)試集表現(xiàn) y_pred_ens predict(mdl_ens, X_test_std); y_pred_svm predict(mdl_svm, X_test_std); acc_ens sum(y_pred_ens y_test) / numel(y_test); acc_svm sum(y_pred_svm y_test) / numel(y_test); fprintf(Ensemble: %.2f%% | SVM: %.2f%%\n, acc_ens*100, acc_svm*100);AdaBoostM2是面對(duì)多分類時(shí)比較穩(wěn)妥的提升方法二分類可以用AdaBoostM1或LogitBoost。NumLearningCycles對(duì)應(yīng)弱學(xué)習(xí)器數(shù)量100 是起點(diǎn)如果測(cè)試精度還在漲就往上加。templateSVM里的BoxConstraint是 SVM 的懲罰系數(shù)越大越強(qiáng)調(diào)分類正確、越容易過(guò)擬合1 是相對(duì)中庸的起點(diǎn)KernelScale, auto讓 MATLAB 自己估計(jì)核寬度省事但偶爾會(huì)選到次優(yōu)值后續(xù)調(diào)參時(shí)應(yīng)該改成手動(dòng)搜索。決策樹在這個(gè)工具箱里的定位比較尷尬——單棵樹的精度通常不夠但它有兩個(gè)不可替代的價(jià)值一是特征重要性排序predictorImportance二是作為集成學(xué)習(xí)的基學(xué)習(xí)器。你可以先用fitctree跑一棵淺樹看看哪些特征被優(yōu)先分裂這比盲目的 PCA 降維更能保留業(yè)務(wù)可解釋性。3.2 回歸任務(wù)fitrlinear 和 fitrensemble 的分工回歸方面工具箱提供了從線性回歸fitlm到廣義加性模型fitrgam再到集成回歸fitrensemble的完整梯度。fitlm適合做基線——它輸出的 p 值和系數(shù)置信區(qū)間能快速告訴你哪些變量顯著雖然精度一般但可解釋性最好。數(shù)據(jù)量大的時(shí)候萬(wàn)級(jí)以上fitrlinear值得優(yōu)先試因?yàn)樗陔S機(jī)雙梯度下降在稀疏高維數(shù)據(jù)上速度快得離譜。但如果你手里的數(shù)據(jù)集不超過(guò)幾千行最快、最準(zhǔn)的往往是fitrensemble搭配LSBoost% 集成回歸梯度提升 mdl_r fitrensemble(X_train_std, y_train, ... Method, LSBoost, ... NumLearningCycles, 200, ... LearnRate, 0.1); % 預(yù)測(cè)與評(píng)估 y_pred_r predict(mdl_r, X_test_std); rmse sqrt(mean((y_pred_r - y_test).^2)); r2 1 - sum((y_test - y_pred_r).^2) / sum((y_test - mean(y_test)).^2); fprintf(RMSE %.4f, R2 %.4f\n, rmse, r2);LearnRate學(xué)習(xí)率是梯度提升里最關(guān)鍵的參數(shù)。0.1 是保守起步值訓(xùn)練集 RMSE 會(huì)穩(wěn)步下降降到 0.01 可以讓精度小幅提升但要付出 510 倍的訓(xùn)練輪數(shù)大于 0.3 基本無(wú)需嘗試測(cè)試集精度很容易抖成噪聲。NumLearningCycles和學(xué)習(xí)率是一對(duì)組合拳學(xué)習(xí)率越小需要的迭代次數(shù)越多可以用ValidationData參數(shù)單獨(dú)傳驗(yàn)證集讓 MATLAB 自動(dòng)輸出每個(gè)迭代周期的驗(yàn)證誤差曲線plot(loss(mdl_r, X_test_std, y_test, Mode, cumulative))看曲線什么時(shí)候開始反彈那就是過(guò)擬合的起點(diǎn)。3.3 聚類和降維kmeans 之外的另類選擇聚類場(chǎng)景下kmeans和evalclusters的組合是絕大多數(shù)人停下來(lái)的地方但工具箱里有一個(gè)被低估的函數(shù)dbscan基于密度的聚類。它不需要預(yù)設(shè)簇?cái)?shù)能自動(dòng)識(shí)別噪聲點(diǎn)對(duì)形狀不規(guī)則的數(shù)據(jù)比 kmeans 健壯得多。如果你手里的數(shù)據(jù)不是幾團(tuán)球狀分布dbscan值得在kmeans之前先跑一次。% 基于密度的聚類自動(dòng)確定簇個(gè)數(shù) idx_db dbscan(X_train_std, 0.5, 10); % epsilon0.5, minpts10 % 聚類效果可視化拉成二維用散點(diǎn)圖粗看 gscatter(X_train_std(:,1), X_train_std(:,2), idx_db);dbscan的兩個(gè)參數(shù)epsilon鄰域半徑和minpts最少點(diǎn)數(shù)決定聚類結(jié)果。epsilon太小會(huì)把一個(gè)簇拆成碎片太大又會(huì)把多個(gè)簇合并掉實(shí)戰(zhàn)中通常先用knnsearch對(duì)每個(gè)樣本求第 K 近鄰距離畫一個(gè)排序圖在曲線拐彎處選擇epsilon。minpts一般取特征維數(shù)的兩倍不要小于 5否則噪聲判定失去意義。聚類完成后用silhouette函數(shù)算輪廓系數(shù)高于 0.5 算可接受低于 0.25 基本說(shuō)明聚類結(jié)構(gòu)不明顯別硬解釋。降維方面pca函數(shù)可以輸出主成分系數(shù)、得分和解釋方差但要注意pca默認(rèn)對(duì)列做中心化但不做標(biāo)準(zhǔn)化。如果不同特征的量綱差異巨大先手動(dòng)標(biāo)準(zhǔn)化再喂給pca否則前幾個(gè)主成分會(huì)被量綱大的特征主導(dǎo)得到的主成分圖完全沒意義。工具箱還提供了tsnet-SNE 降維它特別適合把高維數(shù)據(jù)降到二維做可視化探索但tsne的結(jié)果每次運(yùn)行會(huì)有差異隨機(jī)初始化復(fù)現(xiàn)時(shí)記得固定隨機(jī)種子。4. 黑匣子怎么打開特征選擇、超參數(shù)搜索和模型解釋4.1 用predictorImportance和fsrftest在建模前砍掉噪聲特征建模之前最值錢的一步是特征篩選。工具箱提供了兩類手段過(guò)濾式按統(tǒng)計(jì)檢驗(yàn)篩選和嵌入式用模型輸出的重要性篩選。fsrftest是過(guò)濾式的代表它對(duì)每個(gè)特征單獨(dú)做 F 檢驗(yàn)返回 p 值predictorImportance則是嵌入式——訓(xùn)練完一棵決策樹或集成模型后直接輸出每個(gè)特征在分裂中被使用的總增益占比。% 過(guò)濾式F 檢驗(yàn)選擇 top-k 特征 [idx_sorted, scores] fsrftest(X_train_std, y_train); % 畫出特征得分排序前幾個(gè)特征如果得分?jǐn)嘌率较碌槐A羟懊娴募纯?bar(scores(idx_sorted)); xlabel(特征序號(hào)); ylabel(F 檢驗(yàn)得分); % 嵌入式樹模型的特征重要性 mdl_tree_simple fitctree(X_train_std, y_train, MaxNumSplits, 20); imp predictorImportance(mdl_tree_simple); [~, sortedIdx] sort(imp, descend); disp(sortedIdx(1:min(10, numel(imp)))); % 輸出最重要的前 10 個(gè)特征序號(hào)過(guò)濾式的優(yōu)勢(shì)是快但它的致命缺陷是假設(shè)特征獨(dú)立——兩個(gè)單獨(dú)看都沒用的特征組合起來(lái)可能非常強(qiáng)反之兩個(gè)單獨(dú)很強(qiáng)的特征可能高度冗余。所以我一般先跑fsrftest做粗篩砍掉明顯無(wú)信息的再跑樹模型的重要性做細(xì)篩兩輪都保留下來(lái)的特征才建議進(jìn)最終模型。4.2fitcauto一鍵自動(dòng)建模能信多少坑在哪里從 R2021a 開始工具箱加入了fitcauto和fitrauto它們會(huì)自動(dòng)嘗試多種模型、做特征選擇、調(diào)超參數(shù)最后輸出一個(gè)“自動(dòng)選好的”模型。聽上去像后悔藥但實(shí)際操作中最有價(jià)值的部分不是最終模型而是自動(dòng)搜索過(guò)程中的日志——它會(huì)打印出每種配置的驗(yàn)證精度這比你自己盲猜參數(shù)要高效得多% 自動(dòng)分類建模指定優(yōu)化變量數(shù) mdl_auto fitcauto(X_train_std, y_train, ... OptimizeHyperparameters, auto, ... HyperparameterOptimizationOptions, struct(... MaxObjectiveEvaluations, 30, ... ShowPlots, true, ... UseParallel, true));MaxObjectiveEvaluations是貝葉斯優(yōu)化的迭代輪數(shù)30 是一個(gè)折中值——太少搜不到好參數(shù)太多耗時(shí)成倍增長(zhǎng)。UseParallel設(shè)為true能利用多核加速但并行池啟動(dòng)本身有開銷數(shù)據(jù)量小于 1000 行時(shí)不建議開。這個(gè)函數(shù)不會(huì)幫你做數(shù)據(jù)清洗和特征工程它只優(yōu)化模型部分前端的臟數(shù)據(jù)問題它無(wú)能為力。自動(dòng)模型的可解釋性也比較差用于交差或者快速試探?jīng)]問題用于生產(chǎn)環(huán)境前一定要手動(dòng)驗(yàn)證并固定參數(shù)重新訓(xùn)練。4.3 超參數(shù)手動(dòng)搜索的一個(gè)有效慣例先粗后細(xì)先范圍后精度自動(dòng)優(yōu)化能省時(shí)間但你要理解它背后的貝葉斯優(yōu)化在做什么。工具箱的optimizableVariablebayesopt這套底層接口適合那些需要自定義目標(biāo)函數(shù)的場(chǎng)景比如你不僅要優(yōu)化精度還要懲罰模型的復(fù)雜度或者要求誤報(bào)率低于某個(gè)閾值。bayesopt的核心邏輯是先隨機(jī)采樣幾個(gè)點(diǎn)然后用高斯過(guò)程擬合“參數(shù)→目標(biāo)函數(shù)”的映射再通過(guò)采集函數(shù)默認(rèn)expected-improvement選擇下一個(gè)最有潛力的點(diǎn)去評(píng)估。這意味著它能主動(dòng)避開明顯差的區(qū)域把評(píng)估預(yù)算花在刀刃上。實(shí)戰(zhàn)中一個(gè)可靠的做法是先放開范圍粗搜 3050 次找到相對(duì)好的區(qū)域然后縮窄范圍再搜 20 次讓模型在小范圍里精雕細(xì)琢。直接上來(lái)就窄范圍搜索很可能錯(cuò)過(guò)真正的最優(yōu)區(qū)域因?yàn)樨惾~斯優(yōu)化的初始探索階段太短。5. 避坑指南我用這個(gè)工具箱三年攢下的五條翻車記錄5.1 變量名是 string 還是 cell決定你后面要不要對(duì)著索引哭現(xiàn)象代碼跑到fitcsvm報(bào)錯(cuò)提示 Predictor names must be a cell array of character vectors或者預(yù)測(cè)時(shí)predict輸出的變量名帶引號(hào)怪里怪氣。原因readtable默認(rèn)把文本變量讀成 cell 數(shù)組當(dāng)你用data.Properties.VariableNames去匹配列名時(shí)得到的類型是cell但如果用readtable(..., TextType, string)同樣的操作返回的是string類型。工具箱內(nèi)部接口早期對(duì)這兩種類型支持不統(tǒng)一報(bào)錯(cuò)信息又不夠直觀讓人卡半天找不到地方。解決建模前統(tǒng)一執(zhí)行一行data.Properties.VariableNames matlab.lang.makeValidName(data.Properties.VariableNames);把變量名清洗成合法格式同時(shí)保證所有列名都以char類型存在。如果你是從矩陣轉(zhuǎn) table 創(chuàng)建的變量干脆在創(chuàng)建時(shí)用VariableNames, {col1,col2,...}顯式指定不要貪圖省事留默認(rèn)名Var1, Var2——后面做特征篩選和結(jié)果解釋了會(huì)非常痛苦。5.2table里混入的NaN會(huì)靜默改變聚類和 KNN 的距離計(jì)算現(xiàn)象kmeans和dbscan跑完聚類結(jié)果里多了一堆孤立的“簇”或者 KNN 的分類精度低到離譜但你檢查輸入矩陣并沒有明顯問題。原因table類型的數(shù)據(jù)列可以容納NaN而 KNN 計(jì)算距離時(shí)遇到NaN會(huì)把該樣本的距離直接置為缺失工具箱的默認(rèn)行為是跳過(guò)這些樣本而不是報(bào)錯(cuò)。你看到的是精度下降實(shí)際是大量樣本在距離計(jì)算階段就被丟棄了。解決建模前顯式處理缺失值rmmissing刪整行或者fillmissing用中位數(shù)/均值填充。我常在劃分?jǐn)?shù)據(jù)集之前跑一次data rmmissing(data);先看看刪掉多少行如果刪掉超過(guò) 15%就要考慮是不是數(shù)據(jù)采集流程有問題而不是簡(jiǎn)單丟棄。聚類任務(wù)用rmmissing更穩(wěn)妥因?yàn)樘畛洳僮鲿?huì)引入人為信號(hào)扭曲密度的真實(shí)分布。5.3 高版本參數(shù)名不兼容R2023b 的腳本拿到 R2021a 跑不起來(lái)現(xiàn)象換一臺(tái)裝了老版本 MATLAB 的機(jī)器跑腳本報(bào)錯(cuò)Invalid argument name TextType或者Standardize不可用。原因工具箱每年都在加參數(shù)和改默認(rèn)值readtable的TextType參數(shù)在 R2021b 之后才穩(wěn)定fitcknn的Standardize參數(shù)也是 R2021a 新增。同一套代碼在不同版本間的行為差異比想象中大特別是默認(rèn)值的變化——有些函數(shù)在老版本里默認(rèn)不做標(biāo)準(zhǔn)化新版本默認(rèn)做導(dǎo)致同樣代碼在不同機(jī)器上結(jié)果對(duì)不上。解決腳本開頭用ver(stats)打印工具箱版本號(hào)在關(guān)鍵函數(shù)調(diào)用前用if exist(SomeFunction, file)判斷函數(shù)是否存在分支處理。對(duì)于需要長(zhǎng)期保存的腳本寫完第一版后立刻在目標(biāo)機(jī)器上用R2021a級(jí)別的-release參數(shù)重新跑一遍冒煙測(cè)試不要默認(rèn)所有人的環(huán)境和你一致。涉及fitcauto這種新函數(shù)的代碼老版本直接跑不了——提前在腳本說(shuō)明文件里寫明最低版本要求。5.4 分類問題千萬(wàn)別把標(biāo)簽放進(jìn)標(biāo)準(zhǔn)化范圍里現(xiàn)象做完標(biāo)準(zhǔn)化后fitcsvm訓(xùn)練直接崩潰或者訓(xùn)練成功但預(yù)測(cè)結(jié)果全是一個(gè)類別。原因有人在用normalize(data)對(duì)整個(gè) table 做標(biāo)準(zhǔn)化時(shí)把標(biāo)簽列也一起標(biāo)準(zhǔn)化了。對(duì)于數(shù)值型標(biāo)簽回歸問題這意味著標(biāo)簽被縮放后續(xù) RMSE 計(jì)算全錯(cuò)對(duì)于分類標(biāo)簽通常是 categorical 類型標(biāo)準(zhǔn)化直接報(bào)錯(cuò)。這種錯(cuò)誤的典型來(lái)源是把 X 和 y 拼在一個(gè) matrix 里忘了分開處理。解決數(shù)據(jù)導(dǎo)入后第一時(shí)間用y data.label; X data(:, 1:end-1);把標(biāo)簽拆出來(lái)獨(dú)立存放后續(xù)所有預(yù)處理都只對(duì) X 操作。如果是多列標(biāo)簽比如多任務(wù)回歸單獨(dú)存成單獨(dú)的矩陣絕不和特征混在一個(gè)矩陣?yán)镞^(guò)標(biāo)準(zhǔn)化和 PCA。養(yǎng)成這個(gè)習(xí)慣能避免至少 30% 的建模階段低級(jí)報(bào)錯(cuò)。5.5 并行計(jì)算池沒關(guān)干凈導(dǎo)致反復(fù)重開 MATLAB現(xiàn)象跑完fitcauto或bayesopt后MATLAB 內(nèi)存占用異常高再跑別的任務(wù)明顯變卡關(guān)了 MATLAB 重開才好。原因UseParallel為true的優(yōu)化過(guò)程會(huì)啟動(dòng)并行池parpool計(jì)算完成后并行池不會(huì)被自動(dòng)關(guān)閉它一直在后臺(tái)占著內(nèi)存和 CPU 核心。如果你連續(xù)跑多個(gè)優(yōu)化任務(wù)每個(gè)任務(wù)開一個(gè)新的并行池內(nèi)存會(huì)指數(shù)級(jí)上漲。解決優(yōu)化代碼結(jié)束后手動(dòng)加一行delete(gcp(nocreate));先檢查是否存在并行池存在就關(guān)閉。如果你的工作流是“一次性跑一堆優(yōu)化任務(wù)”可以在腳本開頭統(tǒng)一開一個(gè)并行池把所有任務(wù)跑完再關(guān)比每個(gè)任務(wù)單獨(dú)開合池要省去大量重復(fù)啟動(dòng)時(shí)間。另外并行池默認(rèn)的Processes數(shù)量等于 CPU 邏輯核心數(shù)對(duì) 8 核以上的機(jī)器建議手動(dòng)限制為parpool(4)留些資源給 MATLAB 主線程做交互繪圖和數(shù)據(jù)管理。6. 把訓(xùn)練好的模型打包成可用的東西CompactModel、代碼生成和定時(shí)重訓(xùn)的完整閉環(huán)模型訓(xùn)練完只是第一步難點(diǎn)在于讓它能在別人手里、別的機(jī)器上跑起來(lái)。工具箱提供了一條完成度很高的部署鏈路訓(xùn)練好的模型對(duì)象里包含全部訓(xùn)練數(shù)據(jù)比如 KNN 和 SVM 都要存支持向量用compact方法可以丟棄冗余信息生成CompactClassificationModel而saveLearnerForCoder則能把模型變成 C 代碼生成器可以消費(fèi)的格式% 壓縮模型體積去掉訓(xùn)練數(shù)據(jù)引用只保留預(yù)測(cè)所需的核心參數(shù) mdl_compact compact(mdl_svm); saveLearnerForCoder(mdl_compact, svm_model); % 生成一段用于 C 代碼生成的預(yù)測(cè)函數(shù) % 在 MATLAB Coder 里把 svm_model.mat 和下面這個(gè)函數(shù)一起打包 function label predict_svm(X) %#codegen mdl loadLearnerForCoder(svm_model); label predict(mdl, X); endloadLearnerForCoder和saveLearnerForCoder這對(duì)接口是整個(gè)工具箱里最容易被忽略的生產(chǎn)力工具。它們支持大部分常見模型SVM、KNN、決策樹、集成模型、判別分析生成的預(yù)測(cè)函數(shù)可以被 MATLAB Coder 編譯成 C/C 代碼也可以直接部署到 Simulink 模型里做實(shí)時(shí)推理。要注意的是compact之后有些模型方法比如resubPredict查看訓(xùn)練集表現(xiàn)不再可用部署前先用測(cè)試集驗(yàn)證完精度再壓縮壓縮后無(wú)法恢復(fù)原始模型所以保留一份未壓縮的原件是必備的后悔藥。對(duì)于數(shù)據(jù)分布隨時(shí)間漂移的場(chǎng)景比如設(shè)備狀態(tài)監(jiān)測(cè)、價(jià)格預(yù)測(cè)一個(gè)實(shí)用的慣例是把“定時(shí)重訓(xùn) 模型版本記錄”做成一個(gè)獨(dú)立腳本用exist檢查模型文件是否存在來(lái)決定是加載舊模型還是重新訓(xùn)練。另外訓(xùn)練完成后立刻用save(model_full.mat, mdl, X_train_std, y_train, mu, sigma)把訓(xùn)練數(shù)據(jù)、標(biāo)準(zhǔn)化參數(shù)和模型一起存下來(lái)這樣以后任何一次模型迭代你都能用同一套測(cè)試集做公平對(duì)比不會(huì)因?yàn)閾Q了數(shù)據(jù)劃分方式而沒法定位性能變化到底來(lái)自模型還是來(lái)自數(shù)據(jù)。我自己的習(xí)慣是每次訓(xùn)練完都順手把confusionchart或回歸殘差圖plotResiduals(mdl_r)截圖存檔一個(gè)月后再翻出來(lái)對(duì)照數(shù)據(jù)漂移情況。模型的精度變化很多時(shí)候不是模型退化了而是輸入的分布變了只有留好了訓(xùn)練時(shí)的基線快照才能快速區(qū)分這兩種情況。希望這些積累能幫你在 Statistics and Machine Learning Toolbox 里少走幾段彎路把時(shí)間真正花在分析和決策上。本文還有配套的精品資源點(diǎn)擊獲取