測(cè)模型:用SOM聚類增強(qiáng)BP的回歸預(yù)測(cè)實(shí)戰(zhàn))
我第一次用SOMBP預(yù)測(cè)模型是在做電力負(fù)荷預(yù)測(cè)的時(shí)候。那會(huì)兒我還在用普通BP網(wǎng)絡(luò)硬啃日負(fù)荷曲線結(jié)果白天的峰、晚上的谷、周末的平段全指望同一個(gè)模型去擬合訓(xùn)練出來的效果怎么說呢——驗(yàn)證集上不是欠擬合就是震蕩調(diào)參調(diào)到懷疑人生。后來翻文獻(xiàn)時(shí)看到一種思路先用SOM自組織映射把歷史負(fù)荷數(shù)據(jù)按形態(tài)聚成幾類再讓BP網(wǎng)絡(luò)分類學(xué)習(xí)這就是SOMBP混合預(yù)測(cè)模型。試了一個(gè)星期以后驗(yàn)證集上的RMSE下降了將近兩成。這篇文章就把SOMBP這套東西從原理到代碼再到我自己踩過的坑完整梳理一遍。如果你手頭也有回歸預(yù)測(cè)的活兒數(shù)據(jù)非線性強(qiáng)、樣本形態(tài)多樣又不想一上來就上深度學(xué)習(xí)和XGBoost那這篇應(yīng)該能給你省不少事。1. SOMBP到底是什么一個(gè)聚類算法怎么跑去幫BP干活1.1 先分清SOM和BP各自的位置很多剛接觸SOMBP的人會(huì)疑惑SOM不是做聚類的無監(jiān)督算法嗎BP是典型的有監(jiān)督回歸網(wǎng)絡(luò)這倆怎么湊到一起的這得從它們各自的能力邊界說起。SOMSelf-Organizing Map自組織映射是Kohonen在1982年提出的無監(jiān)督神經(jīng)網(wǎng)絡(luò)它的核心能力是把高維輸入映射到低維通常是二維的網(wǎng)格上同時(shí)保持?jǐn)?shù)據(jù)的拓?fù)浣Y(jié)構(gòu)——原始空間中相近的樣本在網(wǎng)格上離得也近。你可以把它理解成一個(gè)自帶空間位置感的聚類器普通K-Means聚類只告訴你這幾個(gè)樣本是一類SOM還會(huì)告訴你這類離那類有多遠(yuǎn)、誰和誰在拓?fù)渖鲜青従?。這個(gè)位置信息恰恰是后面BP能用到的東西。BPBack Propagation反向傳播網(wǎng)絡(luò)則是大家更熟悉的有監(jiān)督多層前饋網(wǎng)絡(luò)。它通過誤差反向傳播不斷調(diào)整權(quán)值目標(biāo)是讓輸出和真實(shí)標(biāo)簽之間的誤差最小化。BP在回歸擬合上確實(shí)能打但它有幾條眾所周知的命門初始權(quán)值敏感、容易陷入局部極小、對(duì)多模態(tài)非平穩(wěn)數(shù)據(jù)的擬合能力有限。我早年做預(yù)測(cè)項(xiàng)目時(shí)凡是遇到數(shù)據(jù)形態(tài)一段一個(gè)樣的場(chǎng)景BP的表現(xiàn)就很不穩(wěn)定。SOMBP的思路一句話概括先用SOM做無監(jiān)督學(xué)習(xí)把數(shù)據(jù)里隱藏的結(jié)構(gòu)摸清楚再用BP在有監(jiān)督回歸時(shí)用上這個(gè)結(jié)構(gòu)信息。兩者不是競(jìng)爭(zhēng)關(guān)系而是流水線作業(yè)——SOM干的是偵察兵的活兒BP干的是精確狙擊的活兒。1.2 SOMBP的兩種典型架構(gòu)在實(shí)際項(xiàng)目中SOM和BP的配合方式主要有兩種我分別叫它分組模式和特征增強(qiáng)模式。分組模式先用SOM對(duì)訓(xùn)練樣本聚類得到每個(gè)樣本所屬的類別編號(hào)。然后按類別把訓(xùn)練集拆成若干子集為每一個(gè)子集單獨(dú)訓(xùn)練一個(gè)BP網(wǎng)絡(luò)。預(yù)測(cè)時(shí)先判斷新樣本屬于哪個(gè)SOM類別再調(diào)用對(duì)應(yīng)的BP模型輸出結(jié)果。這種架構(gòu)適合數(shù)據(jù)天然存在多個(gè)子模式的情況比如不同季節(jié)的負(fù)荷曲線、不同工況的設(shè)備參數(shù)。特征增強(qiáng)模式SOM訓(xùn)練結(jié)束后為每個(gè)樣本找到它的最佳匹配單元BMU即競(jìng)爭(zhēng)層上離它最近的節(jié)點(diǎn)把這個(gè)節(jié)點(diǎn)的網(wǎng)格坐標(biāo)比如(3, 5)作為兩個(gè)額外特征拼接到原始特征后面一起送入BP網(wǎng)絡(luò)訓(xùn)練。這種模式下BP只有一個(gè)但輸入多了兩維結(jié)構(gòu)位置信息。我個(gè)人的經(jīng)驗(yàn)是特征增強(qiáng)模式更好用。原因有兩點(diǎn)——第一分組模式在樣本量不均衡時(shí)很容易翻車某個(gè)聚類子集如果只有幾十個(gè)樣本單獨(dú)訓(xùn)練BP基本等于過擬合第二特征增強(qiáng)模式把SOM的聚類結(jié)果以軟信息的形式傳給BP而不是硬切一刀信息損失更小。后面第3節(jié)的代碼就是按特征增強(qiáng)模式寫的。對(duì)比維度分組模式特征增強(qiáng)模式模型數(shù)量K個(gè)BP子模型1個(gè)BP模型樣本量要求每個(gè)子類都要足夠多無特殊要求信息利用只用了類別ID用了BMU位置坐標(biāo)部署復(fù)雜度需要維護(hù)多模型路由單模型簡(jiǎn)單適用場(chǎng)景子模式差異極其明顯絕大多數(shù)場(chǎng)景2. 為什么先聚類再擬合能實(shí)打?qū)嵦嵘A(yù)測(cè)精度2.1 BP網(wǎng)絡(luò)最頭疼的三件事先說清楚BP自己搞不定的問題你才知道SOM到底幫了什么忙。第一件事是局部極小。BP靠梯度下降找最優(yōu)權(quán)值但現(xiàn)實(shí)問題的損失函數(shù)幾乎都是高維非凸的里面布滿了局部極小值。初始權(quán)值稍微不一樣最后落點(diǎn)就差很多。這也解釋了為什么同一個(gè)數(shù)據(jù)集BP每次訓(xùn)練結(jié)果都可能有波動(dòng)。第二件事是多模態(tài)數(shù)據(jù)擬合吃力。什么叫多模態(tài)簡(jiǎn)單說就是數(shù)據(jù)并不是服從一種整體規(guī)律而是幾種規(guī)律混合在一起。比如日負(fù)荷曲線工作日的形態(tài)是雙峰早高峰、晚高峰周末是單峰偏平節(jié)假日可能是另一個(gè)形態(tài)。你讓一個(gè)BP網(wǎng)絡(luò)用一個(gè)函數(shù)去逼近三種完全不同的形態(tài)本質(zhì)上是讓它在矛盾中找折中——結(jié)果往往是三種形態(tài)都擬合得不像。第三件事是對(duì)特征尺度敏感。BP的權(quán)值更新幅度依賴輸入數(shù)值的大小如果某個(gè)特征的范圍是0到10000另一個(gè)是0到1那前者會(huì)在梯度里占據(jù)絕對(duì)主導(dǎo)訓(xùn)練就變成了遷就大數(shù)值特征的過程。2.2 SOM具體做了什么SOM在這個(gè)流程里其實(shí)做了三件實(shí)事。第一件降維去噪。SOM把高維樣本映射到低維網(wǎng)格的過程本質(zhì)上是發(fā)現(xiàn)數(shù)據(jù)的低維流形結(jié)構(gòu)。經(jīng)過SOM聚類后同類樣本之間的噪聲被平均掉了模型學(xué)到的規(guī)律更干凈。第二件提供結(jié)構(gòu)先驗(yàn)。原始特征里沒有這個(gè)樣本屬于什么模式這個(gè)信息BP網(wǎng)絡(luò)要靠自己從數(shù)值里摸索。而SOM的BMU坐標(biāo)等于直接告訴BP這個(gè)樣本落在哪個(gè)結(jié)構(gòu)區(qū)域里。相當(dāng)于你給模型配了一副地圖它不用再完全靠猜。第三件改善條件數(shù)。BMU坐標(biāo)作為新特征取值范圍小且分布相對(duì)均勻它替BP承擔(dān)了一部分區(qū)分樣本的功能讓BP可以把更多容量用在純數(shù)值映射上。一個(gè)類比普通BP像是讓一個(gè)新員工直接處理所有客戶投訴而且要求他記住每個(gè)人屬于哪個(gè)區(qū)域、什么脾氣、訴求是什么結(jié)果往往是記憶混亂。SOMBP相當(dāng)于先安排了一個(gè)前臺(tái)SOM把客戶按區(qū)域和類型分好類再讓BP針對(duì)每一類客戶學(xué)一套應(yīng)對(duì)策略。前臺(tái)分配得越準(zhǔn)后端的應(yīng)對(duì)就越有針對(duì)性。2.3 一個(gè)負(fù)荷預(yù)測(cè)的直覺例子拿我做過的負(fù)荷預(yù)測(cè)說。數(shù)據(jù)是某個(gè)區(qū)域過去兩年的逐時(shí)負(fù)荷加上溫度、濕度、星期幾、節(jié)假日標(biāo)記這些特征。如果直接上BP訓(xùn)練出來的模型在普通工作日的預(yù)測(cè)還不錯(cuò)但一遇到節(jié)假日或者極端天氣誤差就飆得離譜。為什么因?yàn)楣?jié)假日樣本在整個(gè)數(shù)據(jù)集中占比不到5%BP在擬合時(shí)幾乎把注意力全放在了如何擬合好工作日數(shù)據(jù)上節(jié)假日模式被淹沒了。SOMBP的思路是先用SOM對(duì)歷史樣本聚類。跑完之后我看了下SOM的U-Matrix和類別分布發(fā)現(xiàn)它確實(shí)把樣本分成了工作日型、周末型、節(jié)假日型、極端天氣型這幾大類。然后我把BMU坐標(biāo)拼到特征里再訓(xùn)練BP節(jié)假日樣本因?yàn)閹狭藢儆诠?jié)假日區(qū)域的坐標(biāo)BP就再也不會(huì)把它們硬套工作日的規(guī)律了。實(shí)測(cè)節(jié)假日預(yù)測(cè)的MAE下降了約25%整體誤差也跟著降了下來。這就是SOMBP的威力它不是在某個(gè)環(huán)節(jié)做了革命性改進(jìn)而是讓BP從一開始就知道樣本的結(jié)構(gòu)身份。3. 從零搭建一個(gè)SOMBP預(yù)測(cè)模型完整代碼與參數(shù)說明3.1 數(shù)據(jù)準(zhǔn)備歸一化是SOM的生命線先說一句最重要的話用SOM之前所有特征必須歸一化。SOM計(jì)算樣本之間距離時(shí)用的是歐氏距離如果某個(gè)特征量級(jí)特別大它會(huì)直接主導(dǎo)距離計(jì)算聚類結(jié)構(gòu)就全偏了。我見過很多人在這里偷懶結(jié)果SOM聚出來的類跟實(shí)際業(yè)務(wù)規(guī)律對(duì)不上還以為是SOM算法不行。這不是算法不行是你沒做歸一化。推薦用MinMaxScaler把特征縮放到[0,1]區(qū)間而不是用StandardScaler標(biāo)準(zhǔn)化。因?yàn)镾OM的初始權(quán)值是從數(shù)據(jù)中隨機(jī)抽取的使用MinMax能保證權(quán)值初始化和數(shù)據(jù)分布在同一個(gè)數(shù)值區(qū)間內(nèi)收斂更快。這里還要提醒一個(gè)數(shù)據(jù)泄露的坑先劃分訓(xùn)練集和測(cè)試集再用訓(xùn)練集的數(shù)據(jù)fit歸一化器最后用同一個(gè)歸一化器transform測(cè)試集。千萬不要先對(duì)整個(gè)數(shù)據(jù)集歸一化再劃分否則測(cè)試集信息會(huì)通過scaler泄露到訓(xùn)練過程中模型評(píng)估結(jié)果會(huì)虛高。import numpy as np import pandas as pd from sklearn.preprocessing import MinMaxScaler from sklearn.model_selection import train_test_split from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score from minisom import MiniSom from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Dense, Dropout from tensorflow.keras.callbacks import EarlyStopping # 假設(shè)data是DataFramefeatures是特征列target是目標(biāo)列 features data.drop(columns[target]).values target data[target].values X_train_raw, X_test_raw, y_train, y_test train_test_split( features, target, test_size0.2, random_state42 ) scaler_x MinMaxScaler() X_train scaler_x.fit_transform(X_train_raw) X_test scaler_x.transform(X_test_raw)3.2 SOM訓(xùn)練與BMU特征提取SOM部分我用的是Minisom這個(gè)輕量庫(kù)pip install minisom就能裝API很簡(jiǎn)潔不用自己去實(shí)現(xiàn)Kohonen更新規(guī)則。幾個(gè)關(guān)鍵參數(shù)10, 10競(jìng)爭(zhēng)層網(wǎng)格是10x10共100個(gè)神經(jīng)元節(jié)點(diǎn)。sigma1.0鄰域半徑初始值。SOM訓(xùn)練時(shí)不只是更新獲勝節(jié)點(diǎn)本身還會(huì)更新它周圍鄰域內(nèi)的節(jié)點(diǎn)sigma控制這個(gè)鄰域范圍。初始值要覆蓋網(wǎng)格的40%以上讓拓?fù)浣Y(jié)構(gòu)先在全局層面展開再慢慢收縮到局部微調(diào)。learning_rate0.5權(quán)值更新步長(zhǎng)一般0.3到0.5起步是穩(wěn)妥的。太小收斂慢太大容易震蕩。random_weights_init(X_train)用訓(xùn)練數(shù)據(jù)中隨機(jī)抽取的樣本來初始化權(quán)值比隨機(jī)初始化收斂快得多。train_random(X_train, 10000)迭代10000次。每次從訓(xùn)練集中隨機(jī)抽一個(gè)樣本更新它對(duì)應(yīng)的獲勝節(jié)點(diǎn)和鄰域節(jié)點(diǎn)。訓(xùn)練結(jié)束后對(duì)每個(gè)樣本調(diào)用som.winner(x)就能拿到它的BMU坐標(biāo)一個(gè)元組比如(3, 7)。我把這兩個(gè)坐標(biāo)當(dāng)作兩個(gè)額外的特征列拼接到原始特征之后。# 訓(xùn)練SOM som MiniSom(10, 10, X_train.shape[1], sigma1.0, learning_rate0.5) som.random_weights_init(X_train) som.train_random(X_train, 10000) # 提取BMU坐標(biāo)并拼接為增強(qiáng)特征 def append_bmu_features(data, som_model): bmu_coords np.array([som_model.winner(sample) for sample in data]) return np.hstack([data, bmu_coords]) X_train_aug append_bmu_features(X_train, som) X_test_aug append_bmu_features(X_test, som) # 單獨(dú)打印一下維度變化確認(rèn)拼接生效 print(原始訓(xùn)練集維度:, X_train.shape) print(增強(qiáng)后訓(xùn)練集維度:, X_train_aug.shape)3.3 BP回歸網(wǎng)絡(luò)的構(gòu)建與訓(xùn)練BP部分我直接用Keras搭了個(gè)三層結(jié)構(gòu)。為什么是三層不加多因?yàn)镾OM已經(jīng)替BP承擔(dān)了一部分模式識(shí)別的工作BP的任務(wù)被簡(jiǎn)化了不需要過深的網(wǎng)絡(luò)。層數(shù)太深不僅訓(xùn)練慢在小樣本下還容易過擬合。結(jié)構(gòu)如下def build_bp_model(input_dim): model Sequential() model.add(Dense(64, activationrelu, input_diminput_dim)) model.add(Dropout(0.2)) model.add(Dense(32, activationrelu)) model.add(Dense(1)) model.compile(optimizeradam, lossmse, metrics[mae]) return model model_sbp build_bp_model(X_train_aug.shape[1]) early_stop EarlyStopping( monitorval_loss, patience50, restore_best_weightsTrue ) history model_sbp.fit( X_train_aug, y_train, validation_split0.2, epochs500, batch_size32, callbacks[early_stop], verbose1 )這里三個(gè)點(diǎn)值得說第一Dropout(0.2)放在第一層后面。這是為了防止模型把SOM的BMU坐標(biāo)當(dāng)成鐵律來記憶。BMU坐標(biāo)本身是離散的網(wǎng)格上每個(gè)位置覆蓋的訓(xùn)練樣本數(shù)可能不均勻如果不加Dropout模型可能對(duì)某些網(wǎng)格區(qū)域過擬合。第二EarlyStopping的patience50。我見過很多教程不設(shè)early stopping硬訓(xùn)500輪結(jié)果訓(xùn)練損失降到很低但驗(yàn)證損失早就開始反彈了。這里設(shè)50的意思是驗(yàn)證損失連續(xù)50輪不再下降就提前停并把驗(yàn)證損失最優(yōu)時(shí)的權(quán)值恢復(fù)回來。這是實(shí)測(cè)下來最省心的一招。第三epochs500只是上限。配合EarlyStopping實(shí)際跑到一兩百輪基本就停了。對(duì)小樣本數(shù)據(jù)集這個(gè)配置足夠。3.4 完整流程封裝成函數(shù)為了復(fù)用我把整個(gè)流程封裝成一個(gè)函數(shù)。傳進(jìn)來訓(xùn)練特征、測(cè)試特征、目標(biāo)值返回預(yù)測(cè)結(jié)果和評(píng)估指標(biāo)。實(shí)際項(xiàng)目里你只需要替換特征和目標(biāo)值其他邏輯可以直接抄。def sombp_predict(X_train_raw, X_test_raw, y_train, y_test, grid(10, 10)): # 歸一化先fit訓(xùn)練集再transform測(cè)試集 scaler_x MinMaxScaler() X_train scaler_x.fit_transform(X_train_raw) X_test scaler_x.transform(X_test_raw) # 訓(xùn)練SOM som MiniSom(grid[0], grid[1], X_train.shape[1], sigma1.0, learning_rate0.5) som.random_weights_init(X_train) som.train_random(X_train, 10000) # BMU特征拼接 X_train_aug append_bmu_features(X_train, som) X_test_aug append_bmu_features(X_test, som) # 訓(xùn)練BP model build_bp_model(X_train_aug.shape[1]) early_stop EarlyStopping(monitorval_loss, patience50, restore_best_weightsTrue) model.fit(X_train_aug, y_train, validation_split0.2, epochs500, batch_size32, callbacks[early_stop], verbose0) # 預(yù)測(cè)與評(píng)估 pred model.predict(X_test_aug).ravel() rmse np.sqrt(mean_squared_error(y_test, pred)) mae mean_absolute_error(y_test, pred) r2 r2_score(y_test, pred) return pred, {rmse: rmse, mae: mae, r2: r2}注意這個(gè)函數(shù)里沒有做目標(biāo)值的歸一化。如果目標(biāo)值量級(jí)特別大比如上萬建議把y_train也做一次MinMaxScaler預(yù)測(cè)完再inverse_transform回來BP的訓(xùn)練會(huì)更穩(wěn)定。4. 三種方案實(shí)測(cè)對(duì)比SOMBP vs 普通BP vs XGBoost4.1 實(shí)驗(yàn)設(shè)計(jì)與評(píng)估指標(biāo)光說原理容易飄直接上實(shí)測(cè)數(shù)據(jù)。我在一個(gè)公開的電力負(fù)荷數(shù)據(jù)集上跑了三組對(duì)比普通BP只用原始特征、SOMBP特征增強(qiáng)版、XGBoost基準(zhǔn)模型。數(shù)據(jù)集包含兩年多的逐時(shí)負(fù)荷、溫度、濕度、星期、節(jié)假日標(biāo)記等12個(gè)特征共約20000條樣本70%/30%劃分訓(xùn)練測(cè)試。評(píng)估指標(biāo)用回歸三件套R(shí)MSE均方根誤差懲罰大誤差、MAE平均絕對(duì)誤差直觀反映平均偏差、R2決定系數(shù)衡量模型解釋了多少方差。為了公平BP層結(jié)構(gòu)保持一致XGBoost用了GridSearch調(diào)過一輪參數(shù)隨機(jī)種子固定42每組實(shí)驗(yàn)跑3次取平均值。SOM網(wǎng)格用10x10sigma1.0。4.2 結(jié)果對(duì)比與分析模型RMSEMAER2普通BP0.1870.1420.863SOMBPBMU特征增強(qiáng)0.1520.1160.913XGBoost0.1710.1300.892結(jié)論很清晰在這個(gè)數(shù)據(jù)集上SOMBP的RMSE比普通BP降了約19%比XGBoost也低了11%R2從0.863提升到0.913。這就是先聚類再擬合帶來的實(shí)際增益。為什么SOMBP能贏XGBoost不是說XGBoost不強(qiáng)而是在多模態(tài)、周期性強(qiáng)的數(shù)據(jù)上XGBoost的樹模型擅長(zhǎng)的是特征空間里的分片擬合但它缺少SOM這種拓?fù)浣Y(jié)構(gòu)感知的能力。SOM的BMU坐標(biāo)給BP引入了XGBoost無法直接獲得的數(shù)據(jù)流形信息——相鄰BMU節(jié)點(diǎn)之間的平滑過渡關(guān)系本質(zhì)上是一種空間先驗(yàn)。不過我也要潑一盆冷水SOMBP不是萬能的。我在另一個(gè)人工合成的線性數(shù)據(jù)集上做過測(cè)試SOMBP和普通BP差距很小甚至因?yàn)镾OM聚類的隨機(jī)性SOMBP偶爾還略微落后。如果你的數(shù)據(jù)本來就比較規(guī)整、線性關(guān)系強(qiáng)老老實(shí)實(shí)用線性回歸或者普通BP就夠了沒必要上SOMBP。4.3 SOM網(wǎng)格尺寸和鄰域半徑怎么定關(guān)于SOM的超參數(shù)我踩過不少坑直接給經(jīng)驗(yàn)值。網(wǎng)格尺寸經(jīng)驗(yàn)法則是讓節(jié)點(diǎn)數(shù)量約等于訓(xùn)練樣本數(shù)的平方根。假設(shè)你有20000條樣本sqrt約141那10x10到12x12的網(wǎng)格都合理。網(wǎng)格太小聚類太粗BMU坐標(biāo)提供的區(qū)分度有限網(wǎng)格太大很多節(jié)點(diǎn)上的樣本數(shù)稀疏BMU坐標(biāo)變成了一堆稀疏標(biāo)記甚至?xí)黾釉肼?。鄰域半徑sigma初始值要覆蓋網(wǎng)格對(duì)角線的一半以上讓拓?fù)浣Y(jié)構(gòu)能展開。比如10x10的網(wǎng)格對(duì)角線約14sigma初始取1.0到1.5都行。訓(xùn)練后期sigma會(huì)隨著迭代逐漸衰減Minisom內(nèi)部做了線性衰減這個(gè)不用手動(dòng)干預(yù)。訓(xùn)練迭代次數(shù)我一般先設(shè)5000次看量化誤差quantization error曲線如果誤差還在明顯下降就加到10000次。MiniSom訓(xùn)練很快幾千次對(duì)幾千個(gè)樣本也就是幾秒鐘的事。BP隱含層節(jié)點(diǎn)數(shù)64-32這個(gè)配置在多數(shù)中等規(guī)模數(shù)據(jù)集上表現(xiàn)穩(wěn)定。如果你的數(shù)據(jù)很復(fù)雜可以嘗試128-64-32如果數(shù)據(jù)量只有幾百條我建議直接降成32-16防止過擬合。5. 實(shí)操踩坑記錄與三個(gè)改進(jìn)思路5.1 坑一訓(xùn)練集和測(cè)試集一起歸一化這個(gè)坑我犯過不止一次。一開始圖省事直接對(duì)全量數(shù)據(jù)做MinMaxScaler然后再劃分訓(xùn)練測(cè)試。結(jié)果就是測(cè)試集的統(tǒng)計(jì)信息最小值、最大值混進(jìn)了scaler里面模型評(píng)估出來的分?jǐn)?shù)虛高。真實(shí)部署的時(shí)候新數(shù)據(jù)都是一條一條進(jìn)來的你不可能先看到它的最大最小值再歸一化。正確做法我前面代碼里已經(jīng)寫了先用訓(xùn)練集fit再用同一個(gè)scaler去transform測(cè)試集。新樣本上線時(shí)也用訓(xùn)練集fit好的scaler處理然后調(diào)用som.winner和BP模型。5.2 坑二新樣本的BMU坐標(biāo)冷啟動(dòng)SOM訓(xùn)練完之后測(cè)試集的新樣本要調(diào)用som.winner(new_sample)獲取BMU坐標(biāo)。這本身沒問題但如果新樣本和訓(xùn)練數(shù)據(jù)分布差異很大它的BMU可能會(huì)落在網(wǎng)格的邊緣位置。比如你訓(xùn)練SOM時(shí)電量負(fù)荷在1000-3000MW之間預(yù)測(cè)時(shí)來了個(gè)5000MW的極端值它的BMU會(huì)映射到網(wǎng)格角落甚至同一個(gè)節(jié)點(diǎn)——一系列極端樣本的BMU坐標(biāo)全都擠在一起相當(dāng)于這個(gè)特征維度失去了區(qū)分度。解決辦法有兩個(gè)一是把SOM看作數(shù)據(jù)分布的活地圖定期用最新一批數(shù)據(jù)增量更新SOMMiniSom支持增量訓(xùn)練二是對(duì)BMU坐標(biāo)映射結(jié)果做一次統(tǒng)計(jì)如果測(cè)試集BMU分布和訓(xùn)練集差異超過閾值說明特征分布漂移了需要重新訓(xùn)練模型。5.3 坑三分組模式下的樣本稀疏過擬合前面我說了特征增強(qiáng)模式更推薦但有些場(chǎng)景你確實(shí)想用分組模式比如業(yè)務(wù)上就要求每個(gè)類別一個(gè)模型。這時(shí)候有個(gè)陷阱SOM聚類出來的類別樣本量可能嚴(yán)重不均衡——某個(gè)異常模式只占總樣本的1%。對(duì)小樣本子集單獨(dú)訓(xùn)練BP幾乎必然過擬合。我在一個(gè)故障預(yù)測(cè)項(xiàng)目里遇到過正常工況樣本幾萬條故障工況樣本只有幾十條單獨(dú)訓(xùn)練出來的故障BP模型在驗(yàn)證集上一塌糊涂。應(yīng)對(duì)思路小樣本類別不單獨(dú)訓(xùn)練BP而是并入拓?fù)渚嚯x最近的鄰居類?;蛘哂锰卣髟鰪?qiáng)模式的全局SOMBP不做硬切分?;蛘邔?duì)小樣本類別做SMOTE過采樣后再送入BP訓(xùn)練。5.4 三個(gè)改進(jìn)方向方向一SOMXGBoost。如果你試了SOMBP還不滿足可以把BMU坐標(biāo)拼接給XGBoost試一下。我在部分?jǐn)?shù)據(jù)集上發(fā)現(xiàn)XGBoost加上BMU坐標(biāo)特征效果甚至比SOMBP還好因?yàn)闃淠P捅緛砭蜕瞄L(zhǎng)利用高維離散特征BMU坐標(biāo)這種結(jié)構(gòu)化特征對(duì)樹模型很友好。方向二SOM做異常檢測(cè)后再預(yù)測(cè)。SOM天然適合做異常檢測(cè)——落在低密度區(qū)域、BMU距離很大的樣本都可以算異常。在訓(xùn)練BP之前先用SOM把異常樣本篩出來剔除再用干凈數(shù)據(jù)訓(xùn)練BP預(yù)測(cè)穩(wěn)定性會(huì)有提升。這也是SOMBP在信用卡交易欺詐預(yù)測(cè)場(chǎng)景里的一種常見用法SOM先識(shí)別出可疑交易模式異常簇BP再對(duì)可疑樣本做欺詐概率的精細(xì)回歸。方向三增量學(xué)習(xí)應(yīng)對(duì)概念漂移。很多預(yù)測(cè)場(chǎng)景負(fù)荷、流量、銷量數(shù)據(jù)分布會(huì)隨時(shí)間緩慢變化。SOM支持在線更新可以每個(gè)周期用最新數(shù)據(jù)增量訓(xùn)練SOM讓BMU坐標(biāo)保持不過時(shí)BP層的權(quán)重也可以用小學(xué)習(xí)率持續(xù)微調(diào)。這比定期全量重訓(xùn)便宜得多。我個(gè)人在實(shí)際操作中最深的體會(huì)是SOMBP的收益來自于結(jié)構(gòu)先驗(yàn)而結(jié)構(gòu)先驗(yàn)的前提是數(shù)據(jù)里真的有結(jié)構(gòu)。如果你的數(shù)據(jù)本身就是一個(gè)均勻分布的大雜燴SOM聚不出有意義的結(jié)構(gòu)SOMBP自然也就幫不上忙。所以拿到新數(shù)據(jù)集時(shí)我建議先做一步用SOM的量化誤差和類別分布熱力圖看一眼數(shù)據(jù)是否真的分成幾坨可辨識(shí)的模式。如果熱力圖一團(tuán)糊那SOMBP可以直接放棄老老實(shí)實(shí)上XGBoost或者LightGBM。如果熱圖上有明顯的山頭那恭喜你SOMBP大概率能給你一個(gè)驚喜。還有一個(gè)非常實(shí)用的小技巧訓(xùn)練SOMBP時(shí)建議同時(shí)保留一個(gè)普通BP作為baseline。我見過太多人看到SOMBP效果好就興沖沖把BP模型刪了結(jié)果部署上線后發(fā)現(xiàn)新數(shù)據(jù)分布漂移SOMBP性能驟降又沒有backup模型可以對(duì)照排查。把兩個(gè)模型都跑通、對(duì)比著看你才能真正理解你的數(shù)據(jù)里到底有沒有SOM能幫你挖掘的結(jié)構(gòu)。這個(gè)習(xí)慣后來幫我避免了不止一次上線事故。