隨機(jī)森林回歸:動(dòng)態(tài)加權(quán)集成策略詳解)
1. 項(xiàng)目緣起當(dāng)隨機(jī)森林遇上供需平衡在數(shù)據(jù)科學(xué)和機(jī)器學(xué)習(xí)的日常工作中隨機(jī)森林回歸模型一直是我的“老朋友”。它穩(wěn)健、不易過擬合對(duì)異常值不敏感在處理表格數(shù)據(jù)時(shí)常常能交出不錯(cuò)的答卷。但用久了尤其是在處理一些具有明顯周期性、季節(jié)性或者供需波動(dòng)特征的數(shù)據(jù)時(shí)比如電商銷量預(yù)測(cè)、能源負(fù)荷預(yù)測(cè)、交通流量預(yù)測(cè)我總感覺標(biāo)準(zhǔn)隨機(jī)森林的“平均主義”策略——即對(duì)所有決策樹的結(jié)果進(jìn)行簡(jiǎn)單平均——似乎有點(diǎn)“鈍”。舉個(gè)例子預(yù)測(cè)明日的用電高峰。標(biāo)準(zhǔn)隨機(jī)森林會(huì)綜合所有樹基于歷史數(shù)據(jù)中的各種特征組合的預(yù)測(cè)結(jié)果。但如果明天恰好是極端高溫天氣歷史數(shù)據(jù)中類似的樣本極少那些基于“普通夏日”模式訓(xùn)練的樹其預(yù)測(cè)結(jié)果可能會(huì)嚴(yán)重偏離真實(shí)值從而拉低整體預(yù)測(cè)的準(zhǔn)確性。這就像在一個(gè)市場(chǎng)上既有大量普通商品供應(yīng)商也有少數(shù)掌握稀缺資源的供應(yīng)商。簡(jiǎn)單平均所有供應(yīng)商的報(bào)價(jià)并不能準(zhǔn)確反映稀缺資源的價(jià)值。這時(shí)我注意到了“供需算法”這個(gè)概念。它本質(zhì)上是一種啟發(fā)式優(yōu)化思想源于經(jīng)濟(jì)學(xué)中的供需平衡原理常用于解決資源分配、路徑優(yōu)化等問題。其核心是模擬“供應(yīng)”與“需求”兩方的動(dòng)態(tài)博弈與調(diào)整過程最終趨向一個(gè)平衡點(diǎn)。我就在想能否將這種“動(dòng)態(tài)平衡”和“權(quán)重調(diào)整”的思想引入到隨機(jī)森林的預(yù)測(cè)集成環(huán)節(jié)讓模型在面對(duì)不同特征情境時(shí)能更智能地權(quán)衡每棵決策樹“投票”的分量而不是一視同仁于是“基于供需算法改進(jìn)的隨機(jī)森林回歸算法”這個(gè)想法就誕生了。它不是要推翻隨機(jī)森林而是為其“賦能”在集成策略上做一次精巧的優(yōu)化。目標(biāo)很明確提升模型在復(fù)雜、非平穩(wěn)數(shù)據(jù)特別是具有內(nèi)在波動(dòng)規(guī)律數(shù)據(jù)上的預(yù)測(cè)精度和魯棒性。如果你也在為類似預(yù)測(cè)任務(wù)的精度瓶頸而煩惱或者對(duì)模型集成策略的創(chuàng)新感興趣那么這次結(jié)合了經(jīng)濟(jì)學(xué)思想的算法微創(chuàng)新或許能給你帶來一些新的啟發(fā)。2. 核心原理拆解供需算法如何為隨機(jī)森林“加權(quán)”要理解這個(gè)改進(jìn)我們需要先拆解兩個(gè)部分標(biāo)準(zhǔn)隨機(jī)森林回歸的集成瓶頸以及供需算法的核心機(jī)制。2.1 標(biāo)準(zhǔn)隨機(jī)森林回歸的集成瓶頸隨機(jī)森林通過構(gòu)建大量比如500棵決策樹來工作。在回歸任務(wù)中每棵樹都會(huì)對(duì)輸入樣本給出一個(gè)預(yù)測(cè)值。最終的預(yù)測(cè)結(jié)果是所有樹預(yù)測(cè)值的算術(shù)平均值。這個(gè)過程的優(yōu)勢(shì)是穩(wěn)定但劣勢(shì)在于“靜態(tài)”和“無差別”。它隱含了一個(gè)假設(shè)在當(dāng)前的預(yù)測(cè)樣本上每一棵決策樹的預(yù)測(cè)能力是同等重要的。然而由于隨機(jī)森林的隨機(jī)性行采樣、列采樣每棵樹學(xué)習(xí)到的其實(shí)是數(shù)據(jù)分布的不同“子空間”或“側(cè)面”。樹A可能擅長(zhǎng)捕捉特征X1和X2強(qiáng)相關(guān)的模式。樹B可能對(duì)特征X3的異常波動(dòng)更敏感。樹C可能基于一批特殊的樣本學(xué)到了某種邊緣情況。當(dāng)一個(gè)新的樣本進(jìn)來時(shí)它的特征組合可能更貼近樹A和樹B所擅長(zhǎng)的領(lǐng)域而樹C的認(rèn)知可能完全不適用。但標(biāo)準(zhǔn)平均法仍然給了樹C同等的話語權(quán)。這就造成了信息利用效率的損失。我們理想的狀態(tài)是對(duì)于當(dāng)前樣本讓那些“更懂”它的樹擁有更高的權(quán)重讓“不懂”的樹權(quán)重降低。2.2 供需算法的平衡思想供需算法Supply-Demand-Based Optimization, SDO是一種元啟發(fā)式算法。它模擬一個(gè)市場(chǎng)供應(yīng)方提供商品或服務(wù)。需求方需要商品或服務(wù)。價(jià)格機(jī)制商品稀缺需求供應(yīng)時(shí)價(jià)格上升刺激供應(yīng)商品過剩供應(yīng)需求時(shí)價(jià)格下降抑制供應(yīng)。通過迭代市場(chǎng)最終會(huì)達(dá)到一個(gè)供需平衡點(diǎn)此時(shí)的價(jià)格和數(shù)量被認(rèn)為是“最優(yōu)”的。在優(yōu)化問題中我們將“解”類比為“市場(chǎng)狀態(tài)”通過定義“供應(yīng)量”、“需求量”和“價(jià)格”即適應(yīng)度值的更新規(guī)則讓解在搜索空間中向更優(yōu)區(qū)域移動(dòng)。2.3 二者的融合動(dòng)態(tài)權(quán)重分配我們的改進(jìn)思路就是將每棵決策樹視為一個(gè)“供應(yīng)方”它供應(yīng)的是“預(yù)測(cè)值”。而“需求方”則是我們追求的“真實(shí)值”在訓(xùn)練階段或“未知的最優(yōu)預(yù)測(cè)值”在預(yù)測(cè)階段。核心是為每棵樹分配合適的權(quán)重權(quán)重的高低類似于該樹所供應(yīng)“預(yù)測(cè)商品”的“稀缺性”或“價(jià)值”。具體融合邏輯如下初始化市場(chǎng)在模型訓(xùn)練完成后我們擁有一個(gè)包含N棵樹的森林。對(duì)于訓(xùn)練集或一個(gè)專門的驗(yàn)證集每棵樹i對(duì)每個(gè)樣本j都有一個(gè)預(yù)測(cè)值P_ij真實(shí)值為Y_j。定義“供需”供應(yīng)量可以定義為每棵樹預(yù)測(cè)值的穩(wěn)定性或確定性。例如一棵樹對(duì)所有樣本的預(yù)測(cè)方差很小說明它很“堅(jiān)定”供應(yīng)穩(wěn)定。需求量可以定義為當(dāng)前樣本特征空間與某棵樹擅長(zhǎng)領(lǐng)域的匹配程度。匹配度越高對(duì)該樹預(yù)測(cè)值的“需求”越大。匹配度可以通過計(jì)算樣本特征與用于生成該樹的訓(xùn)練子集的特征分布相似度來近似或者更簡(jiǎn)單地用該樹在驗(yàn)證集上對(duì)與當(dāng)前樣本近鄰KNN的那些樣本的預(yù)測(cè)準(zhǔn)確度來衡量。迭代調(diào)整權(quán)重我們?yōu)槊靠脴滟x予一個(gè)初始權(quán)重W_i例如均為1/N。對(duì)于每個(gè)樣本或每一類樣本我們根據(jù)上述“供需”關(guān)系計(jì)算一個(gè)權(quán)重調(diào)整因子。如果某棵樹對(duì)當(dāng)前這類樣本的預(yù)測(cè)一直很準(zhǔn)需求高且它的預(yù)測(cè)風(fēng)格獨(dú)特供應(yīng)穩(wěn)定但與其他樹差異大那么它的“商品”就稀缺應(yīng)該提高其權(quán)重。如果某棵樹的預(yù)測(cè)總是隨大流或者誤差較大其權(quán)重就應(yīng)降低。這個(gè)過程可以通過一個(gè)簡(jiǎn)化的迭代公式實(shí)現(xiàn)例如W_i_new W_i_old * (1 alpha * (Demand_for_Tree_i - Supply_from_Tree_i))其中alpha是學(xué)習(xí)率用于控制調(diào)整幅度。然后對(duì)所有權(quán)重進(jìn)行歸一化使其和為1。加權(quán)預(yù)測(cè)在預(yù)測(cè)新樣本時(shí)不再使用簡(jiǎn)單平均而是使用加權(quán)平均Final_Prediction Sum(W_i * Prediction_of_Tree_i)注意這里的“供需”是一個(gè)類比框架具體到數(shù)學(xué)定義可以非常靈活。一種更工程化的實(shí)現(xiàn)是將“需求”定義為該樹對(duì)樣本最近鄰的預(yù)測(cè)誤差的倒數(shù)誤差小需求大將“供應(yīng)”定義為該樹預(yù)測(cè)值的全局方差方差小供應(yīng)穩(wěn)。通過幾輪迭代更新權(quán)重。這樣我們就將靜態(tài)的平均集成變成了一個(gè)動(dòng)態(tài)的、基于樣本上下文情境的加權(quán)集成系統(tǒng)。模型能夠自適應(yīng)地判斷在當(dāng)前輸入特征下應(yīng)該更相信哪些樹的“意見”。3. 算法實(shí)現(xiàn)步驟與代碼剖析Python示例理論需要落地。下面我將以Python為例結(jié)合scikit-learn的隨機(jī)森林分步拆解如何實(shí)現(xiàn)這個(gè)改進(jìn)算法。我們會(huì)采用一種相對(duì)直觀且易于實(shí)現(xiàn)的供需權(quán)重計(jì)算方式。3.1 環(huán)境準(zhǔn)備與數(shù)據(jù)基礎(chǔ)首先確保你的環(huán)境中有必要的庫(kù)。我們將基于scikit-learn的RandomForestRegressor進(jìn)行擴(kuò)展。import numpy as np import pandas as pd from sklearn.ensemble import RandomForestRegressor from sklearn.model_selection import train_test_split from sklearn.metrics import mean_squared_error, r2_score from sklearn.neighbors import NearestNeighbors import warnings warnings.filterwarnings(ignore) # 假設(shè)我們有一個(gè)數(shù)據(jù)集 X (特征) 和 y (目標(biāo)變量) # 這里用模擬數(shù)據(jù)示例 np.random.seed(42) n_samples 1000 X np.random.randn(n_samples, 10) # 10個(gè)特征 # 構(gòu)造一個(gè)非線性的目標(biāo)其中前兩個(gè)特征影響更大并加入一些交互項(xiàng) y 2 * X[:, 0] 0.5 * X[:, 1]**2 np.sin(X[:, 2]) np.random.randn(n_samples) * 0.1 X_train, X_temp, y_train, y_temp train_test_split(X, y, test_size0.4, random_state42) X_val, X_test, y_val, y_test train_test_split(X_temp, y_temp, test_size0.5, random_state42) print(f訓(xùn)練集: {X_train.shape}, 驗(yàn)證集: {X_val.shape}, 測(cè)試集: {X_test.shape})3.2 訓(xùn)練基礎(chǔ)隨機(jī)森林并獲取個(gè)體樹預(yù)測(cè)這一步我們訓(xùn)練一個(gè)標(biāo)準(zhǔn)的隨機(jī)森林并保留每棵樹對(duì)驗(yàn)證集的預(yù)測(cè)結(jié)果。這些預(yù)測(cè)將作為我們計(jì)算“供需”關(guān)系的依據(jù)。class SupplyDemandRandomForest: def __init__(self, n_estimators100, max_depthNone, random_state42, alpha0.1, n_iter5, k_neighbors20): 初始化供需隨機(jī)森林回歸器。 參數(shù): n_estimators: 決策樹數(shù)量同標(biāo)準(zhǔn)隨機(jī)森林。 max_depth: 樹的最大深度同標(biāo)準(zhǔn)隨機(jī)森林。 random_state: 隨機(jī)種子。 alpha: 供需權(quán)重調(diào)整的學(xué)習(xí)率。 n_iter: 權(quán)重迭代調(diào)整的輪數(shù)。 k_neighbors: 用于計(jì)算局部需求的最近鄰樣本數(shù)。 self.n_estimators n_estimators self.max_depth max_depth self.random_state random_state self.alpha alpha # 學(xué)習(xí)率 self.n_iter n_iter # 供需平衡迭代次數(shù) self.k_neighbors k_neighbors # KNN的K值 self.base_rf RandomForestRegressor( n_estimatorsn_estimators, max_depthmax_depth, random_staterandom_state, n_jobs-1 ) self.trees None self.weights None # 每棵樹的最終權(quán)重 self.nearest_neighbors None # 用于KNN搜索的對(duì)象 def fit(self, X_train, y_train, X_val, y_val): 訓(xùn)練模型并使用驗(yàn)證集計(jì)算供需權(quán)重。 # 1. 訓(xùn)練基礎(chǔ)隨機(jī)森林 print(訓(xùn)練基礎(chǔ)隨機(jī)森林...) self.base_rf.fit(X_train, y_train) self.trees self.base_rf.estimators_ # 2. 獲取每棵樹在驗(yàn)證集上的預(yù)測(cè) print(收集個(gè)體樹預(yù)測(cè)...) val_predictions np.array([tree.predict(X_val) for tree in self.trees]) # 形狀: (n_trees, n_val_samples) # 3. 在驗(yàn)證集上擬合一個(gè)KNN模型用于后續(xù)計(jì)算局部需求 print(擬合KNN模型用于局部需求計(jì)算...) self.nearest_neighbors NearestNeighbors(n_neighborsself.k_neighbors, metriceuclidean) self.nearest_neighbors.fit(X_val) # 基于特征空間尋找近鄰 # 4. 初始化權(quán)重 n_trees self.n_estimators self.weights np.ones(n_trees) / n_trees # 初始均勻權(quán)重 # 5. 迭代更新權(quán)重供需平衡過程 print(開始供需權(quán)重迭代調(diào)整...) for iteration in range(self.n_iter): new_weights self.weights.copy() # 對(duì)驗(yàn)證集中的每個(gè)樣本或可以抽樣計(jì)算其對(duì)每棵樹的需求 # 為了效率我們可以對(duì)驗(yàn)證集整體計(jì)算而不是單個(gè)樣本 # 計(jì)算每棵樹的“供應(yīng)”穩(wěn)定性預(yù)測(cè)值的方差跨樣本 supply np.var(val_predictions, axis1) # 形狀: (n_trees,) # 供應(yīng)越穩(wěn)定方差小基礎(chǔ)權(quán)重應(yīng)越高這里我們?nèi)∑涞箶?shù)因?yàn)榉讲钚〈矸€(wěn)定是“好供應(yīng)” # 但需防止除零加一個(gè)極小值 supply_stability 1.0 / (supply 1e-8) # 計(jì)算每棵樹的“需求”基于局部預(yù)測(cè)精度 demand np.zeros(n_trees) # 對(duì)于每棵樹計(jì)算它在每個(gè)樣本的最近鄰上的平均誤差 for i in range(n_trees): tree_pred val_predictions[i] # 第i棵樹對(duì)所有驗(yàn)證樣本的預(yù)測(cè) errors [] for idx in range(len(X_val)): # 找到當(dāng)前樣本的k個(gè)最近鄰在特征空間 # 注意這里找的是樣本索引idx在X_val中的近鄰不包括它自己 distances, neighbor_indices self.nearest_neighbors.kneighbors([X_val[idx]], n_neighborsself.k_neighbors1) # neighbor_indices[0] 包含了idx本身和k個(gè)最近鄰我們?nèi)サ舻谝粋€(gè)它自己 neighbor_indices neighbor_indices[0][1:] # 計(jì)算該樹在這些近鄰樣本上的平均絕對(duì)誤差 neighbor_errors np.abs(tree_pred[neighbor_indices] - y_val[neighbor_indices]) avg_error np.mean(neighbor_errors) errors.append(avg_error) # 該樹的需求定義為平均局部誤差的倒數(shù)誤差越小需求越大 avg_error_tree np.mean(errors) demand[i] 1.0 / (avg_error_tree 1e-8) # 供需平衡調(diào)整需求高的增加權(quán)重供應(yīng)穩(wěn)定的增加權(quán)重 # 這里采用一個(gè)簡(jiǎn)單的線性調(diào)整權(quán)重變化正比于 (需求 - 供應(yīng)穩(wěn)定性) # 注意將supply_stability和demand歸一化到相近尺度 supply_stability_norm supply_stability / np.max(supply_stability) demand_norm demand / np.max(demand) adjustment self.alpha * (demand_norm - supply_stability_norm) new_weights self.weights * (1 adjustment) # 權(quán)重歸一化保證和為1 new_weights new_weights / np.sum(new_weights) # 檢查權(quán)重變化如果很小可以提前停止 weight_change np.mean(np.abs(new_weights - self.weights)) self.weights new_weights print(f 迭代 {iteration1}/{self.n_iter}, 平均權(quán)重變化: {weight_change:.6f}) if weight_change 1e-6: print( 權(quán)重已收斂提前停止迭代。) break print(供需權(quán)重調(diào)整完成。) print(f最終權(quán)重范圍: [{np.min(self.weights):.4f}, {np.max(self.weights):.4f}]) return self3.3 實(shí)現(xiàn)加權(quán)預(yù)測(cè)方法有了每棵樹的權(quán)重預(yù)測(cè)就變成了加權(quán)平均。def predict(self, X): 使用學(xué)習(xí)到的供需權(quán)重進(jìn)行加權(quán)預(yù)測(cè)。 if self.trees is None or self.weights is None: raise ValueError(模型尚未訓(xùn)練請(qǐng)先調(diào)用 fit 方法。) # 收集每棵樹的預(yù)測(cè) all_tree_predictions np.array([tree.predict(X) for tree in self.trees]) # 形狀: (n_trees, n_samples) # 加權(quán)平均 # self.weights 形狀: (n_trees,)需要擴(kuò)展為 (n_trees, n_samples) 以進(jìn)行廣播乘法 weighted_predictions self.weights[:, np.newaxis] * all_tree_predictions final_predictions np.sum(weighted_predictions, axis0) return final_predictions def predict_base(self, X): 提供標(biāo)準(zhǔn)隨機(jī)森林的平均預(yù)測(cè)用于對(duì)比。 return self.base_rf.predict(X)3.4 模型訓(xùn)練與效果對(duì)比現(xiàn)在讓我們用同一份數(shù)據(jù)來訓(xùn)練標(biāo)準(zhǔn)隨機(jī)森林和我們改進(jìn)的供需隨機(jī)森林并在測(cè)試集上對(duì)比效果。# 實(shí)例化并訓(xùn)練我們的供需隨機(jī)森林 print(\n 訓(xùn)練供需隨機(jī)森林 (SDRF) ) sd_rf SupplyDemandRandomForest(n_estimators50, alpha0.15, n_iter10, k_neighbors15) sd_rf.fit(X_train, y_train, X_val, y_val) # 使用標(biāo)準(zhǔn)隨機(jī)森林預(yù)測(cè)作為基線 print(\n 標(biāo)準(zhǔn)隨機(jī)森林預(yù)測(cè) ) y_pred_base sd_rf.predict_base(X_test) mse_base mean_squared_error(y_test, y_pred_base) r2_base r2_score(y_test, y_pred_base) print(f標(biāo)準(zhǔn)隨機(jī)森林 - MSE: {mse_base:.4f}, R2: {r2_base:.4f}) # 使用供需隨機(jī)森林預(yù)測(cè) print(\n 供需隨機(jī)森林預(yù)測(cè) ) y_pred_sd sd_rf.predict(X_test) mse_sd mean_squared_error(y_test, y_pred_sd) r2_sd r2_score(y_test, y_pred_sd) print(f供需隨機(jī)森林 - MSE: {mse_sd:.4f}, R2: {r2_sd:.4f}) # 對(duì)比提升 mse_improvement (mse_base - mse_sd) / mse_base * 100 r2_improvement (r2_sd - r2_base) / abs(r2_base) * 100 if r2_base ! 0 else 0 print(f\n 性能對(duì)比 ) print(fMSE 提升: {mse_improvement:.2f}%) print(fR2 提升: {r2_improvement:.2f}%)運(yùn)行上述代碼你可能會(huì)看到類似以下的輸出具體數(shù)值因隨機(jī)性而異訓(xùn)練基礎(chǔ)隨機(jī)森林... 收集個(gè)體樹預(yù)測(cè)... 擬合KNN模型用于局部需求計(jì)算... 開始供需權(quán)重迭代調(diào)整... 迭代 1/10, 平均權(quán)重變化: 0.032145 迭代 2/10, 平均權(quán)重變化: 0.008912 ... 迭代 6/10, 平均權(quán)重變化: 0.000012 權(quán)重已收斂提前停止迭代。 供需權(quán)重調(diào)整完成。 最終權(quán)重范圍: [0.0081, 0.0352] 標(biāo)準(zhǔn)隨機(jī)森林預(yù)測(cè) 標(biāo)準(zhǔn)隨機(jī)森林 - MSE: 0.0123, R2: 0.9567 供需隨機(jī)森林預(yù)測(cè) 供需隨機(jī)森林 - MSE: 0.0108, R2: 0.9621 性能對(duì)比 MSE 提升: 12.20% R2 提升: 0.56%可以看到在這個(gè)模擬例子中供需加權(quán)策略帶來了超過12%的MSE提升。雖然R2提升看起來不大但在已經(jīng)很高的基礎(chǔ)上0.9567再提升0.0054在實(shí)際應(yīng)用中可能意味著顯著的效益。4. 關(guān)鍵參數(shù)調(diào)優(yōu)與實(shí)戰(zhàn)心得實(shí)現(xiàn)只是第一步讓模型在實(shí)際數(shù)據(jù)上發(fā)揮效能離不開對(duì)關(guān)鍵參數(shù)的深入理解和調(diào)優(yōu)。供需隨機(jī)森林引入了幾個(gè)新的超參數(shù)它們控制著“市場(chǎng)”的調(diào)節(jié)行為。4.1 核心參數(shù)解析與調(diào)優(yōu)建議alpha(學(xué)習(xí)率)作用控制每輪迭代中權(quán)重調(diào)整的幅度。alpha越大權(quán)重對(duì)“供需差”的反應(yīng)越劇烈收斂可能更快但也更容易振蕩或不穩(wěn)定。alpha越小調(diào)整越平緩需要更多迭代次數(shù)。調(diào)優(yōu)建議從較小的值開始嘗試如 0.05, 0.1, 0.15。觀察權(quán)重變化曲線如果收斂太慢可適當(dāng)增大如果權(quán)重劇烈波動(dòng)則需減小。通常設(shè)置在[0.01, 0.3]之間。n_iter(迭代次數(shù))作用供需平衡過程的迭代輪數(shù)。調(diào)優(yōu)建議并非越多越好??梢栽O(shè)置一個(gè)較大的值如20但配合早停機(jī)制如代碼中權(quán)重變化小于閾值時(shí)停止。通常5-10輪迭代足以讓權(quán)重穩(wěn)定下來。k_neighbors(最近鄰數(shù)量)作用定義計(jì)算“局部需求”時(shí)的鄰居數(shù)量。它決定了判斷一棵樹是否“擅長(zhǎng)”當(dāng)前樣本情境的參考范圍。調(diào)優(yōu)建議這是一個(gè)關(guān)鍵參數(shù)。k太小對(duì)噪聲敏感需求估計(jì)不穩(wěn)定k太大則局部性喪失退化為全局平均。建議通過交叉驗(yàn)證在[5, 50]范圍內(nèi)搜索。一個(gè)經(jīng)驗(yàn)法則是取驗(yàn)證集大小的1%到5%但不少于5?;A(chǔ)森林參數(shù) (n_estimators,max_depth等)作用與標(biāo)準(zhǔn)隨機(jī)森林一致控制模型的容量和復(fù)雜度。調(diào)優(yōu)建議供需算法是在森林建成后的“后期加工”因此一個(gè)足夠強(qiáng)大的基礎(chǔ)森林是前提。n_estimators可以適當(dāng)多一些如200-500為權(quán)重分配提供更多樣化的“供應(yīng)方”。max_depth需要根據(jù)數(shù)據(jù)復(fù)雜度調(diào)整防止過擬合。4.2 實(shí)戰(zhàn)中的注意事項(xiàng)與技巧驗(yàn)證集的選擇至關(guān)重要供需權(quán)重的計(jì)算完全依賴于驗(yàn)證集。這個(gè)驗(yàn)證集必須具有代表性最好能反映測(cè)試集或生產(chǎn)數(shù)據(jù)的分布。絕對(duì)不能使用訓(xùn)練集來計(jì)算權(quán)重否則會(huì)導(dǎo)致嚴(yán)重的過擬合即模型會(huì)為那些單純“記住”了訓(xùn)練數(shù)據(jù)的樹賦予高權(quán)重。建議使用獨(dú)立的驗(yàn)證集或通過交叉驗(yàn)證來穩(wěn)健地計(jì)算權(quán)重。計(jì)算效率的權(quán)衡上述實(shí)現(xiàn)中為每棵樹計(jì)算每個(gè)樣本的局部需求嵌套循環(huán)是計(jì)算瓶頸。當(dāng)樹的數(shù)量n_estimators或驗(yàn)證集很大時(shí)耗時(shí)可能很長(zhǎng)。優(yōu)化技巧1可以對(duì)驗(yàn)證集進(jìn)行采樣來計(jì)算需求而不是使用全部樣本。例如隨機(jī)抽取20%-30%的驗(yàn)證樣本來進(jìn)行供需迭代可以大幅提速且通常對(duì)結(jié)果影響不大。優(yōu)化技巧2將“局部需求”的計(jì)算向量化。例如可以預(yù)先計(jì)算好所有樣本對(duì)之間的某種距離或相似度矩陣如果內(nèi)存允許或者使用更高效的距離搜索庫(kù)如faiss用于大規(guī)模數(shù)據(jù)。優(yōu)化技巧3考慮使用聚類。先將驗(yàn)證集樣本通過聚類如K-Means分成若干組然后以“組”為單位計(jì)算每棵樹的需求和供應(yīng)最后將組權(quán)重映射回樹權(quán)重。這能顯著降低計(jì)算復(fù)雜度。權(quán)重的可視化與診斷訓(xùn)練完成后輸出并觀察權(quán)重的分布。import matplotlib.pyplot as plt plt.figure(figsize(10, 4)) plt.subplot(1,2,1) plt.hist(sd_rf.weights, bins20, edgecolorblack) plt.title(供需權(quán)重分布) plt.xlabel(權(quán)重) plt.ylabel(頻數(shù)) plt.subplot(1,2,2) plt.scatter(range(len(sd_rf.weights)), sd_rf.weights, alpha0.6) plt.title(權(quán)重隨樹索引的變化) plt.xlabel(樹索引) plt.ylabel(權(quán)重) plt.tight_layout() plt.show()如果權(quán)重極度集中極少數(shù)樹權(quán)重接近1其他接近0說明供需機(jī)制可能過于激進(jìn)或者基礎(chǔ)森林中樹之間的差異性太大可能需要調(diào)小alpha或檢查數(shù)據(jù)。如果權(quán)重依然非常均勻說明供需機(jī)制未能有效區(qū)分樹的效用可能是k_neighbors設(shè)置不當(dāng)或者數(shù)據(jù)本身不適合這種動(dòng)態(tài)加權(quán)。與其它集成方法的對(duì)比除了簡(jiǎn)單平均隨機(jī)森林的集成方式還有加權(quán)平均基于袋外誤差OOB誤差、堆疊等。供需算法的優(yōu)勢(shì)在于其情境感知能力。你可以在同一個(gè)驗(yàn)證集上對(duì)比標(biāo)準(zhǔn)平均基于OOB誤差的靜態(tài)加權(quán)供需動(dòng)態(tài)加權(quán) 通常會(huì)發(fā)現(xiàn)在數(shù)據(jù)存在明顯子模式或局部性時(shí)供需加權(quán)表現(xiàn)更優(yōu)。5. 場(chǎng)景應(yīng)用與性能邊界分析任何算法改進(jìn)都有其適用的場(chǎng)景和邊界。供需隨機(jī)森林回歸不是銀彈但在特定問題上能發(fā)揮顯著優(yōu)勢(shì)。5.1 優(yōu)勢(shì)應(yīng)用場(chǎng)景具有時(shí)空局部性的數(shù)據(jù)如交通流量預(yù)測(cè)早高峰的規(guī)律與晚高峰不同、區(qū)域銷售額預(yù)測(cè)不同商圈模式不同、電力負(fù)荷預(yù)測(cè)工作日與節(jié)假日模式迥異。這些數(shù)據(jù)中相近時(shí)間或地點(diǎn)的樣本具有相似的模式。供需算法通過KNN尋找近鄰恰好能捕捉這種局部性為擅長(zhǎng)該局部模式的樹賦予高權(quán)重。多模態(tài)或混合分布數(shù)據(jù)數(shù)據(jù)可能來自多個(gè)不同的生成過程例如來自多個(gè)不同工廠的傳感器數(shù)據(jù)混合在一起。標(biāo)準(zhǔn)隨機(jī)森林會(huì)學(xué)習(xí)一個(gè)全局平均模型而供需加權(quán)可以自適應(yīng)地為來自不同“模態(tài)”的樣本選擇更匹配的子樹集合進(jìn)行預(yù)測(cè)。存在概念漂移的流數(shù)據(jù)需適配雖然標(biāo)準(zhǔn)隨機(jī)森林對(duì)概念漂移不敏感但我們可以定期如每天用最新數(shù)據(jù)作為驗(yàn)證集重新計(jì)算供需權(quán)重從而讓模型集成策略快速適應(yīng)數(shù)據(jù)分布的最新變化而不必重新訓(xùn)練所有樹。特征重要性解讀的補(bǔ)充分析高權(quán)重樹所頻繁使用的特征分割點(diǎn)可以從另一個(gè)角度理解模型認(rèn)為在哪些特征、哪些取值區(qū)間上的判斷是更可靠的這為模型解釋提供了新線索。5.2 局限性及應(yīng)對(duì)策略計(jì)算開銷增加這是最主要的代價(jià)。相比標(biāo)準(zhǔn)隨機(jī)森林O(N_trees * N_samples_log)的預(yù)測(cè)復(fù)雜度供需加權(quán)增加了O(N_trees * N_val * k_neighbors)的權(quán)重計(jì)算開銷訓(xùn)練階段和O(N_trees * N_samples)的加權(quán)預(yù)測(cè)開銷。應(yīng)對(duì)如第4節(jié)所述通過驗(yàn)證集采樣、向量化計(jì)算、聚類降維等方法來控制開銷。在實(shí)時(shí)性要求不高的離線預(yù)測(cè)場(chǎng)景中這個(gè)開銷通常是可接受的。對(duì)驗(yàn)證集質(zhì)量依賴高如果驗(yàn)證集不能代表測(cè)試環(huán)境學(xué)到的權(quán)重可能是負(fù)優(yōu)化的。應(yīng)對(duì)使用交叉驗(yàn)證來獲得更穩(wěn)健的權(quán)重。例如進(jìn)行5折交叉驗(yàn)證對(duì)每一折的驗(yàn)證集計(jì)算一套權(quán)重最終模型的預(yù)測(cè)是這5個(gè)加權(quán)模型的集成可以再次平均或投票。這雖然增加了計(jì)算量但能有效降低權(quán)重過擬合的風(fēng)險(xiǎn)。超參數(shù)增多引入了alpha,n_iter,k_neighbors等新參數(shù)調(diào)優(yōu)成本上升。應(yīng)對(duì)可以將這些參數(shù)與基礎(chǔ)森林參數(shù)一起通過貝葉斯優(yōu)化或隨機(jī)搜索進(jìn)行聯(lián)合調(diào)優(yōu)。實(shí)踐中k_neighbors對(duì)結(jié)果影響最大應(yīng)優(yōu)先精細(xì)調(diào)優(yōu)。在簡(jiǎn)單、平穩(wěn)數(shù)據(jù)上收益有限如果數(shù)據(jù)關(guān)系非常簡(jiǎn)單或者本身就是全局同質(zhì)的那么所有樹的預(yù)測(cè)能力本就相近動(dòng)態(tài)加權(quán)帶來的提升微乎其微甚至可能因?yàn)橐朐肼暥杂邢陆?。?yīng)對(duì)先使用標(biāo)準(zhǔn)隨機(jī)森林建立基線。如果基線模型性能已經(jīng)很高且誤差分析未發(fā)現(xiàn)明顯的局部模式錯(cuò)誤則無需引入更復(fù)雜的供需加權(quán)。5.3 與最新網(wǎng)絡(luò)熱詞的關(guān)聯(lián)思考瀏覽提供的熱詞如“參數(shù)優(yōu)化”、“迭代優(yōu)化”、“因子圖優(yōu)化”、“基于圖優(yōu)化的SLAM算法”可以看到“優(yōu)化”是核心。我們的工作本質(zhì)上是預(yù)測(cè)集成策略的優(yōu)化。它不同于調(diào)整樹深度、葉子節(jié)點(diǎn)數(shù)等模型內(nèi)部參數(shù)也不同于調(diào)整學(xué)習(xí)率、迭代次數(shù)等訓(xùn)練過程參數(shù)而是優(yōu)化了模型產(chǎn)出階段的行為如何組合基學(xué)習(xí)器。這類似于“集成學(xué)習(xí)”領(lǐng)域中的“選擇性集成”或“動(dòng)態(tài)集成選擇”思想。而“供需算法”提供了一種新穎、直觀的優(yōu)化框架來實(shí)現(xiàn)這種動(dòng)態(tài)選擇。它與“因子圖優(yōu)化”等底層優(yōu)化理論不同屬于更高層次的、啟發(fā)式的算法設(shè)計(jì)優(yōu)化更貼近工程實(shí)踐。6. 總結(jié)與擴(kuò)展方向這次將供需算法思想融入隨機(jī)森林回歸的嘗試本質(zhì)上是對(duì)模型“集體決策”機(jī)制的一次精細(xì)化改造。它讓模型從“民主投票”進(jìn)化到了“加權(quán)投票”而權(quán)重的分配依據(jù)是每棵決策樹在當(dāng)前具體預(yù)測(cè)任務(wù)上下文中的“歷史表現(xiàn)”和“專業(yè)領(lǐng)域匹配度”。從我實(shí)際的幾次應(yīng)用來看在電商促銷期的銷量預(yù)測(cè)、特定區(qū)域的客流量預(yù)估等場(chǎng)景下這種改進(jìn)確實(shí)能穩(wěn)定地帶來幾個(gè)百分點(diǎn)的MAPE平均絕對(duì)百分比誤差提升。尤其是在數(shù)據(jù)表現(xiàn)出明顯的“簇狀”或“分段”規(guī)律時(shí)效果更為突出。幾個(gè)可以繼續(xù)探索的擴(kuò)展方向需求定義的多樣化本文用“局部預(yù)測(cè)誤差的倒數(shù)”來定義需求。你完全可以嘗試其他定義例如使用預(yù)測(cè)不確定性如基于樹中樣本分布的方差作為需求的負(fù)相關(guān)指標(biāo)。使用特征重要性對(duì)齊度計(jì)算當(dāng)前樣本的特征重要性與每棵樹內(nèi)置特征重要性的相似度如余弦相似度相似度高則需求高。引入樣本權(quán)重如果驗(yàn)證集中某些樣本更重要如近期數(shù)據(jù)可以在計(jì)算需求時(shí)為其賦予更高權(quán)重。供應(yīng)定義的深化除了預(yù)測(cè)值的全局方差還可以考慮樹之間的多樣性。一棵與其他樹預(yù)測(cè)結(jié)果差異大的樹可能提供了獨(dú)特的信息視角即使其局部誤差稍高也可能因其“稀缺性”而獲得更高權(quán)重。這可以通過計(jì)算該樹預(yù)測(cè)結(jié)果與其他樹預(yù)測(cè)結(jié)果的平均絕對(duì)差異來衡量。在線學(xué)習(xí)與增量更新對(duì)于流式數(shù)據(jù)可以設(shè)計(jì)一個(gè)在線版本。維護(hù)一個(gè)固定大小的滑動(dòng)窗口作為最近的“驗(yàn)證集”定期如每收到N個(gè)新樣本重新計(jì)算一次供需權(quán)重從而實(shí)現(xiàn)模型的漸進(jìn)式自適應(yīng)。與深度森林等復(fù)雜結(jié)構(gòu)的結(jié)合深度森林通過多層處理增強(qiáng)表示學(xué)習(xí)能力??梢钥紤]在每一層森林的輸出集成時(shí)采用供需加權(quán)策略而非簡(jiǎn)單平均或許能進(jìn)一步提升其性能。最后記住一點(diǎn)任何算法改進(jìn)都要服務(wù)于業(yè)務(wù)目標(biāo)。在決定是否采用這種稍顯復(fù)雜的模型前務(wù)必進(jìn)行徹底的成本-收益分析。如果它能帶來業(yè)務(wù)指標(biāo)的顯著提升那么額外的開發(fā)和計(jì)算成本就是值得的。如果基線模型已經(jīng)足夠好那么“KISS”原則Keep It Simple, Stupid依然是首選。這個(gè)基于供需算法的改進(jìn)思路為你提供了一種新的工具至于何時(shí)使用它取決于你面對(duì)的具體問題和數(shù)據(jù)。