測算法實(shí)戰(zhàn):從時(shí)間序列到集成學(xué)習(xí)的模型選型與落地)
簡介一份圍繞Python核心預(yù)測算法與源碼實(shí)踐的完整學(xué)習(xí)資料包面向數(shù)據(jù)分析、機(jī)器學(xué)習(xí)入門及進(jìn)階人群系統(tǒng)覆蓋線性回歸、邏輯回歸、決策樹與隨機(jī)森林、支持向量機(jī)、神經(jīng)網(wǎng)絡(luò)、時(shí)間序列分析、梯度提升機(jī)、K近鄰、樸素貝葉斯等常用預(yù)測模型同時(shí)涉及交叉驗(yàn)證、特征選擇、模型評估與數(shù)據(jù)預(yù)處理等關(guān)鍵環(huán)節(jié)適用于學(xué)術(shù)研究及工程實(shí)戰(zhàn)中的預(yù)測建模參考。包體共149個(gè)文件以100個(gè)可直接運(yùn)行的Python腳本為核心配以40個(gè)文本說明、2個(gè)Jupyter交互式筆記本、1個(gè)配套PDF文檔及數(shù)個(gè)子壓縮包整體大小約16MB目錄結(jié)構(gòu)清晰便于按算法或場景分類學(xué)習(xí)。目前已有444人學(xué)習(xí)使用尤其適合希望結(jié)合源代碼深入理解預(yù)測算法原理的讀者。隨附腳本覆蓋巖石-礦井分類、玻璃類型識(shí)別、葡萄酒數(shù)據(jù)等多組實(shí)驗(yàn)場景完整演示數(shù)據(jù)清洗、特征處理、模型調(diào)參與效果評估流程結(jié)合PDF對預(yù)測分析核心算法的講解可幫助讀者快速復(fù)現(xiàn)結(jié)果并遷移到自己的數(shù)據(jù)集上顯著提升實(shí)際項(xiàng)目中的建模與排錯(cuò)能力。1. 記住核心算法預(yù)測真正的門檻在“預(yù)測引擎”的落地把“python核心算法預(yù)測[含源代碼]python核心算法_python預(yù)測_預(yù)測_預(yù)測算法_senseuco”這句長標(biāo)題翻譯成業(yè)務(wù)語言其實(shí)就是用 Python 實(shí)現(xiàn)一個(gè)帶核心算法的預(yù)測模塊跑出自己的預(yù)言結(jié)果。這事聽起來像調(diào)庫真做起來你就會(huì)發(fā)現(xiàn)90% 的翻車現(xiàn)場都不在算法公式而在數(shù)據(jù)對齊、滯后特征構(gòu)造、模型重訓(xùn)策略這些“看起來誰都會(huì)”的地方。我做過的項(xiàng)目里最典型的一類是給運(yùn)營部門做未來 4 周的銷量預(yù)測手里有歷史訂單、采購周期、節(jié)假日標(biāo)記和促銷活動(dòng)記錄。目標(biāo)不是預(yù)測一個(gè)數(shù)而是讓預(yù)測結(jié)果能接進(jìn)下游的補(bǔ)貨計(jì)劃。這里真正有價(jià)值的不是把某個(gè)深度學(xué)習(xí)模型跑通而是把“數(shù)據(jù)清洗 → 特征工程 → 模型選擇 → 參數(shù)調(diào)優(yōu) → 驗(yàn)證 → 重訓(xùn)”這條鏈路做成一個(gè)可持續(xù)運(yùn)行的核心代碼模塊。這篇筆記里我會(huì)直接用一套最小可運(yùn)行的 Python 核心預(yù)測代碼來拆解把時(shí)間序列、回歸、集成樹三種主流方向的選型理由和實(shí)現(xiàn)差異講清楚再把參數(shù)怎么設(shè)、踩坑在哪、驗(yàn)證怎么做一次說完。適合誰看如果你正在給公司搭預(yù)測模塊或者你在做量化交易策略里的價(jià)格預(yù)測又或者你想把自己的預(yù)測想法轉(zhuǎn)成可復(fù)現(xiàn)代碼這篇正好是對著這些訴求寫的。2. 預(yù)測算法的三個(gè)主流方向先選對模型再談?wù){(diào)參2.1 時(shí)間序列算法ARIMA 與指數(shù)平滑的適用邊界時(shí)間序列預(yù)測是最貼近“預(yù)測”二字的一類。它的核心假設(shè)是歷史模式會(huì)延續(xù)未來是過去的某種外推。常見的核心算法包括 ARIMA自回歸積分滑動(dòng)平均、季節(jié)性指數(shù)平滑Holt-Winters以及它們的擴(kuò)展 SARIMA、SARIMAX。ARIMA 的三個(gè)參數(shù) p、d、q 分別對應(yīng)自回歸階數(shù)、差分階數(shù)和移動(dòng)平均階數(shù)。實(shí)際落地時(shí)我一般不會(huì)過度迷信 ACF/PACF 圖而是用網(wǎng)格搜索配合 AIC 或 BIC 信息準(zhǔn)則來定參。原因很簡單手頭數(shù)據(jù)大多是帶噪聲的業(yè)務(wù)數(shù)據(jù)人工看圖定階的主觀誤差遠(yuǎn)大于機(jī)器搜索。指數(shù)平滑家族的優(yōu)點(diǎn)是參數(shù)少、計(jì)算極快、對短期預(yù)測很穩(wěn)適合需要批量預(yù)測幾十個(gè) SKU 的場景。它的短板也很明顯對突變點(diǎn)促銷、斷貨、節(jié)假日沒有感知能力因?yàn)槟P屠餂]有外生變量通道。如果業(yè)務(wù)里促銷是常態(tài)純時(shí)間序列模型只能做基準(zhǔn)線不能做最終決策線。2.2 回歸類算法線性回歸與嶺回歸在預(yù)測中的角色回歸類算法是把預(yù)測問題轉(zhuǎn)成“用若干特征預(yù)測一個(gè)數(shù)值”的監(jiān)督學(xué)習(xí)問題。這個(gè)方向的優(yōu)勢是特征自由度高——你可以在特征矩陣?yán)锶胄瞧趲?、是否?jié)假日、上月銷量、價(jià)格變動(dòng)、庫存周轉(zhuǎn)天數(shù)等任何有業(yè)務(wù)含義的變量。用線性回歸做預(yù)測時(shí)最常踩的坑是多重共線性。比如銷量和銷售額高度相關(guān)同時(shí)進(jìn)模型會(huì)導(dǎo)致系數(shù)不穩(wěn)定、預(yù)測方差變大。常見做法是先用相關(guān)系數(shù)矩陣做一次粗篩再用嶺回歸L2 正則或 LassoL1 正則壓制系數(shù)膨脹。我會(huì)在核心代碼里把 Ridge 作為默認(rèn)回歸器因?yàn)樗燃兙€性回歸穩(wěn)定又比 Lasso 在特征數(shù)不多時(shí)表現(xiàn)得更平滑?;貧w類模型的最大優(yōu)勢是預(yù)測結(jié)果可解釋性極強(qiáng)。運(yùn)營部門問“為什么下周預(yù)測跌了”你能直接指出來是因?yàn)樯现艽黉N基數(shù)太高、這周回歸到正常水平。這在企業(yè)里往往比高一點(diǎn)點(diǎn)的準(zhǔn)確率更值錢。2.3 機(jī)器學(xué)習(xí)集成隨機(jī)森林與 XGBoost 什么時(shí)候值得上當(dāng)特征數(shù)量多、特征和目標(biāo)的因果關(guān)系復(fù)雜時(shí)集成樹算法通常比線性模型效果好一截。隨機(jī)森林對異常值和缺失值更魯棒訓(xùn)練并行化容易調(diào)參成本低。XGBoost 在結(jié)構(gòu)化數(shù)據(jù)上精度更高但對參數(shù)敏感調(diào)不好容易過擬合。我在預(yù)測類項(xiàng)目里的經(jīng)驗(yàn)是先把隨機(jī)森林跑通作為基線再對比 XGBoost。不要一上來就調(diào) XGBoost 的 max_depth、learning_rate、subsample而是先把特征工程做好。特征沒做好換什么模型都是白搭。集成樹還有一個(gè)實(shí)操優(yōu)勢可以輸出特征重要性幫你在每次重訓(xùn)時(shí)驗(yàn)證業(yè)務(wù)假設(shè)——比如“星期幾”的重要性在模型中急劇下降往往是數(shù)據(jù)周期變了或者節(jié)假日規(guī)則變了。2.4 神經(jīng)網(wǎng)絡(luò)方法LSTM 的實(shí)際成本和必要門檻LSTM長短期記憶網(wǎng)絡(luò)在序列預(yù)測里名氣最大但實(shí)際項(xiàng)目里它往往被高估。LSTM 能捕捉長期依賴關(guān)系適合數(shù)據(jù)量足夠大、序列足夠長且存在復(fù)雜非線性模式的場景。但它的訓(xùn)練成本高、調(diào)參復(fù)雜、可解釋性差對數(shù)據(jù)量和特征工程的要求也比樹模型苛刻得多。我的判斷標(biāo)準(zhǔn)很簡單如果訓(xùn)練數(shù)據(jù)少于 1000 條或者預(yù)測目標(biāo)的變化主要由外部業(yè)務(wù)動(dòng)作驅(qū)動(dòng)直接用 LSTM 大概率不如隨機(jī)森林或 XGBoost。LSTM 的用武之地更多在傳感器時(shí)序數(shù)據(jù)、連續(xù)多步預(yù)測這類“規(guī)律性強(qiáng)、外部干擾少”的場景。別為了技術(shù)熱度硬上模型核心算法選型的本質(zhì)是匹配數(shù)據(jù)形態(tài)和業(yè)務(wù)復(fù)雜度。3. 用 Python 實(shí)現(xiàn)預(yù)測最小原型從特征構(gòu)造到核心預(yù)測類3.1 滯后特征與滾動(dòng)窗口把時(shí)間序列轉(zhuǎn)成監(jiān)督學(xué)習(xí)格式時(shí)間序列預(yù)測轉(zhuǎn)監(jiān)督學(xué)習(xí)的核心操作是構(gòu)造滯后特征。滯后特征的含義是用過去 N 步的觀測值作為當(dāng)前預(yù)測步的特征輸入。假設(shè)要預(yù)測明天lag_1 就是今天lag_2 是昨天依此類推。import pandas as pd import numpy as np def make_lag_features(df, target_col, lags(1, 2, 3, 7, 14)): 把時(shí)間序列轉(zhuǎn)成帶滯后特征的監(jiān)督學(xué)習(xí)數(shù)據(jù) data df[[target_col]].copy() for lag in lags: data[flag_{lag}] data[target_col].shift(lag) # 刪除前 max(lags) 行因?yàn)闇蟠翱诓粷M data data.dropna() return data這段代碼的邏輯很簡單對目標(biāo)列做 shift 操作shift(1) 表示把昨天的值拉到今天這一行。選擇 lags(1,2,3,7,14) 是經(jīng)驗(yàn)值覆蓋了短周期1-3 天和中周期7/14 天的慣性。如果業(yè)務(wù)有明顯季節(jié)性比如周末效應(yīng)建議再加入 lag_7 和 lag_28 這類和周期對齊的滯后步長。刪除前 max(lags) 行是必須的因?yàn)榍皫仔袩o法構(gòu)造完整滯后窗口保留下來會(huì)讓模型學(xué)到錯(cuò)誤的填充值。3.2 標(biāo)準(zhǔn)特征集日期特征、節(jié)假日標(biāo)志與均值回環(huán)只靠滯后特征還不夠。預(yù)測的核心算法里日期特征往往決定模型上限。比如銷量預(yù)測中星期幾是重要特征節(jié)假日是更重要的特征。我會(huì)在特征工程塊里統(tǒng)一加上這些def build_feature_set(df, target_col, date_coldate): 從原始表構(gòu)造完整特征集合 data df.copy() data[date_col] pd.to_datetime(data[date_col]) data[weekday] data[date_col].dt.dayofweek # 周一0周日6 data[is_weekend] (data[weekday] 5).astype(int) data[month] data[date_col].dt.month data[day_of_month] data[date_col].dt.day data[is_month_start] (data[day_of_month] 3).astype(int) data[is_month_end] (data[day_of_month] 28).astype(int) # 拼接外部標(biāo)記比如節(jié)假日表 if holiday in data.columns: data[is_holiday] data[holiday].fillna(0).astype(int) return data日期特征的核心價(jià)值是讓模型學(xué)到“周期性規(guī)律”。比如很多零售業(yè)務(wù)的銷量有周末低谷、月初高峰、月底沖量現(xiàn)象。如果把日期直接當(dāng)作數(shù)值型特征輸入模型只會(huì)學(xué)到線性趨勢學(xué)不到周期性。我一般會(huì)把 weekday 保留為 0-6 的整數(shù)方便樹模型做切分。is_weekend、is_month_start 這類二值特征在很多場景里有奇效因?yàn)樗鼈儗?yīng)了業(yè)務(wù)動(dòng)作的錨點(diǎn)。注意 is_month_end 我選 28 而不是 29/30/31是為了讓所有月份都有穩(wěn)定樣本避免 2 月導(dǎo)致的缺失問題。3.3 核心預(yù)測類統(tǒng)一接口封裝多個(gè)算法預(yù)測項(xiàng)目的工程挑戰(zhàn)是換算法成本高。今天用隨機(jī)森林下周試 XGBoost如果代碼里每個(gè)模型都單獨(dú)寫一套訓(xùn)練和預(yù)測邏輯迭代效率很低。我一般會(huì)封裝一個(gè) Predictor 類統(tǒng)一 fit / predict / evaluate 三個(gè)接口內(nèi)部按算法名稱路由。from sklearn.ensemble import RandomForestRegressor from sklearn.linear_model import Ridge from sklearn.metrics import mean_squared_error, mean_absolute_error class CorePredictor: 核心預(yù)測類統(tǒng)一接口按名稱切換算法 def __init__(self, algorithmridge, **params): if algorithm ridge: self.model Ridge(alphaparams.get(alpha, 1.0)) elif algorithm rf: self.model RandomForestRegressor( n_estimatorsparams.get(n_estimators, 200), max_depthparams.get(max_depth, None), random_state42, n_jobs-1, ) else: raise ValueError(f未知算法: {algorithm}) self.algorithm algorithm def fit(self, X_train, y_train): self.model.fit(X_train, y_train) return self def predict(self, X): return self.model.predict(X) def evaluate(self, X_test, y_test): pred self.predict(X_test) rmse float(np.sqrt(mean_squared_error(y_test, pred))) mae float(mean_absolute_error(y_test, pred)) mape float(np.mean(np.abs((y_test - pred) / (y_test 1e-6))) * 100) return {rmse: rmse, mae: mae, mape: mape}這個(gè)類的設(shè)計(jì)意圖是讓訓(xùn)練和評估代碼與具體算法解耦。加一個(gè) XGBoost 只需要在init里增加一個(gè)分支。evaluate() 方法同時(shí)返回 RMSE、MAE、MAPE 三個(gè)指標(biāo)注意 MAPE 計(jì)算里加了 1e-6 防止除零。實(shí)際預(yù)測任務(wù)中RMSE 對大誤差敏感MAE 反映平均偏差水平MAPE 方便向業(yè)務(wù)解釋百分比誤差三者要一起看。3.4 完整預(yù)測流程從原始數(shù)據(jù)到預(yù)測結(jié)果的四步代碼把上述模塊串起來是一個(gè)典型的四步流程讀數(shù)據(jù)、造特征、切分訓(xùn)練測試、訓(xùn)練并預(yù)測。import pandas as pd import numpy as np from sklearn.model_selection import TimeSeriesSplit # 1. 讀取原始數(shù)據(jù) df pd.read_csv(sales_history.csv, parse_dates[date]) df df.sort_values(date).reset_index(dropTrue) # 2. 構(gòu)造特征集 df build_feature_set(df, target_colsales) df make_lag_features(df, target_colsales, lags(1, 2, 3, 7, 14)) # 3. 按時(shí)間順序切分禁止隨機(jī)打亂 feature_cols [c for c in df.columns if c not in (sales, date, holiday)] X df[feature_cols] y df[sales] split_idx int(len(df) * 0.8) X_train, X_test X.iloc[:split_idx], X.iloc[split_idx:] y_train, y_test y.iloc[:split_idx], y.iloc[split_idx:] # 4. 訓(xùn)練與預(yù)測 predictor CorePredictor(algorithmrf, n_estimators300, max_depth8) predictor.fit(X_train, y_train) metrics predictor.evaluate(X_test, y_test) print(預(yù)測指標(biāo):, metrics)這里最關(guān)鍵的是切分方式時(shí)間序列預(yù)測必須按時(shí)間順序切分不能隨機(jī)打亂。如果用了 sklearn 的 train_test_split 默認(rèn) shuffleTrue測試集里混入未來時(shí)間的數(shù)據(jù)模型等于在考試時(shí)看到了答案。TimeSeriesSplit 是更嚴(yán)謹(jǐn)?shù)慕徊骝?yàn)證方式后面第 4 章會(huì)展開說。模型參數(shù)上n_estimators300 是為了讓隨機(jī)森林的預(yù)測方差穩(wěn)定max_depth8 是限制單棵樹復(fù)雜度防止樹模型把訓(xùn)練集的噪聲也學(xué)進(jìn)去。4. 預(yù)測模型參數(shù)設(shè)置用時(shí)間序列交叉驗(yàn)證找到靠譜參數(shù)4.1 滯后窗口長度根據(jù)業(yè)務(wù)周期定而不是拍腦袋滯后特征的長度決定了模型“記住”了多長的歷史。窗口太短模型看不到周期性窗口太長噪聲特征過多反而拖低精度。我的經(jīng)驗(yàn)規(guī)則是至少覆蓋一個(gè)完整業(yè)務(wù)周期。如果業(yè)務(wù)有周周期至少要留 lag_7如果有月度周期則要有 lag_28 ~ lag_31。設(shè)置滯后窗口還有個(gè)實(shí)操技巧不要只用連續(xù)滯后步長比如 (1,2,3,4,5)而是用有代表性的步長比如 (1,2,3,7,14,28)。這么做的原因是多個(gè)連續(xù)滯后特征之間存在高度相關(guān)性比如 lag_1 和 lag_2 在日數(shù)據(jù)上往往高度相似。樹模型還好線性模型就會(huì)出現(xiàn)多重共線性問題。滯后窗口還直接影響訓(xùn)練樣本量。最大滯后值越大能保留的完整樣本行數(shù)越少。比如 lags 最大是 28那么前 28 行都得刪除。如果數(shù)據(jù)只有 300 天刪除 28 行雖然不多但如果你同時(shí)用了 5 年數(shù)據(jù)且按年聚合這個(gè)損失就會(huì)被放大。設(shè)定窗口時(shí)始終要在“記憶長度”和“樣本量”之間取平衡。4.2 隨機(jī)森林與 XGBoost 的核心參數(shù)先調(diào)復(fù)雜度再調(diào)學(xué)習(xí)率隨機(jī)森林有兩個(gè)參數(shù)對預(yù)測結(jié)果影響最大max_depth 和 n_estimators。max_depth 控制樹深度值越大模型越復(fù)雜容易過擬合n_estimators 控制樹的數(shù)量300 棵左右已經(jīng)能穩(wěn)定誤差率再往上加對精度提升很有限只會(huì)增加訓(xùn)練時(shí)間。from sklearn.model_selection import GridSearchCV from sklearn.ensemble import RandomForestRegressor param_grid { max_depth: [4, 6, 8, 10], n_estimators: [200, 300, 500], } model RandomForestRegressor(random_state42, n_jobs-1) tuner GridSearchCV(model, param_grid, cv5, scoringneg_mean_squared_error) tuner.fit(X_train, y_train) print(最優(yōu)參數(shù):, tuner.best_params_)這段代碼用 GridSearchCV 做網(wǎng)格搜索cv5 表示做五折交叉驗(yàn)證。不過在時(shí)間序列場景里cv5 的默認(rèn)交叉驗(yàn)證是隨機(jī)切分有潛在的數(shù)據(jù)泄漏風(fēng)險(xiǎn)。你可以在 GridSearchCV 中傳入自定義的 TimeSeriesSplit或者接受這里的少量偏差先用網(wǎng)格搜索圈定大致區(qū)間再用時(shí)間序列切分做最終驗(yàn)證。XGBoost 的核心參數(shù)更微妙learning_rate 決定每一步的貢獻(xiàn)權(quán)重調(diào)低后需要更多輪次才能收斂max_depth 默認(rèn) 6 對預(yù)測任務(wù)偏高我一般是在 3 到 6 之間嘗試subsample 控制每輪訓(xùn)練采樣比例設(shè)為 0.7-0.9 可以增強(qiáng)泛化能力。優(yōu)先調(diào) max_depth 和 learning_rate不要一開始就動(dòng)正則參數(shù)否則你分不清精度的變化到底來自哪個(gè)動(dòng)作。4.3 時(shí)間序列交叉驗(yàn)證模擬真實(shí)預(yù)測場景的驗(yàn)證方式時(shí)間序列交叉驗(yàn)證和普通 K 折的區(qū)別是訓(xùn)練集永遠(yuǎn)在驗(yàn)證集之前且驗(yàn)證集之間的時(shí)間窗口按順序滾動(dòng)。標(biāo)準(zhǔn)的 TimeSeriesSplit 在 sklearn 里可以直接用。from sklearn.model_selection import TimeSeriesSplit import numpy as np tscv TimeSeriesSplit(n_splits5) rmse_list [] for train_idx, val_idx in tscv.split(X): X_train_fold, X_val_fold X.iloc[train_idx], X.iloc[val_idx] y_train_fold, y_val_fold y.iloc[train_idx], y.iloc[val_idx] model CorePredictor(algorithmrf, n_estimators200, max_depth8) model.fit(X_train_fold, y_train_fold) metrics model.evaluate(X_val_fold, y_val_fold) rmse_list.append(metrics[rmse]) print(5 折時(shí)序交叉驗(yàn)證 RMSE 均值:, np.mean(rmse_list))TimeSeriesSplit(n_splits5) 會(huì)把數(shù)據(jù)切分為 5 個(gè)逐步擴(kuò)張的訓(xùn)練集和對應(yīng)后續(xù)測試。這種驗(yàn)證方式模擬了“用過去預(yù)測未來”的真實(shí)過程比普通 K 折更有參考價(jià)值。注意這里每次折疊都重新訓(xùn)練模型目的是觀察模型在不同時(shí)間段上的穩(wěn)定性。如果某一次的 RMSE 明顯高于其他次說明這段時(shí)間有結(jié)構(gòu)性突變比如大促或者疫情導(dǎo)致的銷量異常你要單獨(dú)標(biāo)記而不是簡單取平均值。4.4 預(yù)測步數(shù)與重訓(xùn)頻率直接決定模型衰減速度預(yù)測步數(shù)指的是你一次預(yù)測未來多少天。單步預(yù)測最簡單誤差最小多步預(yù)測就要考慮誤差累積問題。比如預(yù)測未來 14 天如果用遞歸預(yù)測把第一步預(yù)測結(jié)果當(dāng)作下一步輸入誤差會(huì)逐日累積第 14 天的置信度會(huì)非常低。一種折中是直接多輸出模型把未來 14 天當(dāng)作 14 個(gè)獨(dú)立的回歸目標(biāo)但這樣需要構(gòu)造多標(biāo)簽訓(xùn)練數(shù)據(jù)工程復(fù)雜度更高。重訓(xùn)頻率往往是業(yè)務(wù)落地時(shí)被忽視的核心參數(shù)。數(shù)據(jù)模式會(huì)漂移用戶的購買習(xí)慣會(huì)變、促銷策略會(huì)變、宏觀經(jīng)濟(jì)會(huì)變。我一般會(huì)給預(yù)測模塊加一個(gè)“只讀重訓(xùn)腳本”每天定時(shí)拉取最新數(shù)據(jù)重新計(jì)算特征和訓(xùn)練模型而不是長期復(fù)用舊模型。重訓(xùn)頻率和時(shí)間窗口長度相關(guān)用日數(shù)據(jù)做周預(yù)測至少每周末重訓(xùn)一次用小時(shí)數(shù)據(jù)做天預(yù)測則要每天重訓(xùn)。5. 預(yù)測算法避坑指南最容易翻車的四個(gè)細(xì)節(jié)5.1 數(shù)據(jù)泄漏訓(xùn)練集里混進(jìn)了未來信息指標(biāo)虛高但落地必炸現(xiàn)象交叉驗(yàn)證 RMSE 非常漂亮MAPE 只有 3%上線后預(yù)測結(jié)果卻偏移明顯?;乜创a發(fā)現(xiàn)特征工程里用了全局的標(biāo)準(zhǔn)化參數(shù)。比如用 StandardScaler 在全量數(shù)據(jù)上 fit 后再切分訓(xùn)練集和測試集這就等于讓模型偷看了測試集的均值和方差。原因任何涉及全量數(shù)據(jù)統(tǒng)計(jì)量的操作都會(huì)造成數(shù)據(jù)泄漏。不僅僅是標(biāo)準(zhǔn)化還包括缺失值用全量中位數(shù)填充、全局去趨勢、在全量數(shù)據(jù)上做主成分分析等。解決堅(jiān)持“先切分再加工”的原則。數(shù)據(jù)清洗、特征工程、標(biāo)準(zhǔn)化函數(shù)都先 fit_train再 transform_test。核心做法是把特征構(gòu)造流程封裝成 Pipeline在 Pipeline 內(nèi)部完成 fit 和 transform而不是在原始 DataFrame 上分步操作。5.2 非平穩(wěn)序列直接建模趨勢項(xiàng)被當(dāng)成“萬能規(guī)律”一遇到拐點(diǎn)就翻車現(xiàn)象對帶明顯上升趨勢的業(yè)務(wù)數(shù)據(jù)做 ARIMA 或線性回歸預(yù)測測試集上的誤差還能接受但預(yù)測到未來 10 天時(shí)模型給出了一個(gè)明顯偏高或偏低的值。原因原始序列非平穩(wěn)均值隨時(shí)間變化。序列里的上升趨勢可能只是過去 3 年的業(yè)務(wù)增長不代表未來會(huì)線性增長。模型把趨勢項(xiàng)學(xué)成了一個(gè)確定性外推拐點(diǎn)一旦出現(xiàn)就徹底失效。解決先做平穩(wěn)性檢驗(yàn)。常見的做法是用 statsmodels 的 adfuller 函數(shù)做 ADF 檢驗(yàn)p 值大于 0.05 就認(rèn)為序列非平穩(wěn)需要做一階差分或者去趨勢。差分后再建模預(yù)測結(jié)果要逆差分還原。滯后特征的方差和分布也會(huì)因趨勢而變化所以我一般會(huì)在特征工程里加入時(shí)間索引作為顯式特征讓模型自己決定趨勢項(xiàng)的權(quán)重而不是默認(rèn)線性外推。5.3 節(jié)假日特征處理不當(dāng)用普通的 0/1 標(biāo)志位預(yù)測提前量丟失現(xiàn)象節(jié)假日期間預(yù)測誤差顯著放大尤其是節(jié)假日前 1-2 天和后 1-2 天。原因節(jié)假日對業(yè)務(wù)的影響并不只發(fā)生在那一天。春節(jié)前一周是年貨采購高峰黃金周后一天是出行返程。如果你的節(jié)假日特征只是一個(gè) 0/1 標(biāo)志位模型學(xué)不到“節(jié)前第 3 天開始放量”這種相對時(shí)間規(guī)律。解決把單一標(biāo)志位擴(kuò)展成相對節(jié)假日偏移特征構(gòu)造節(jié)前 n 天、節(jié)后 n 天的窗口特征。比如 is_before_holiday_3、is_after_holiday_1。這種特征能顯著改善節(jié)假日附近步子的預(yù)測精度。另一個(gè)做法是直接引入“距下一個(gè)節(jié)日的天數(shù)”這種連續(xù)特征讓模型自己切分找到規(guī)律。5.4 MAPE 在低頻值下的失真分母極小值讓誤差率爆炸現(xiàn)象評估報(bào)告里 MAPE 高達(dá) 45%但業(yè)務(wù)方覺得預(yù)測結(jié)果“挺準(zhǔn)的”一查發(fā)現(xiàn)是很多天的真實(shí)銷量是 0 或接近 0比如疫情管控階段的門店銷量。原因MAPE 的公式是 abs(實(shí)際值 - 預(yù)測值) / 實(shí)際值實(shí)際值接近 0 時(shí)即使絕對誤差很小百分比也會(huì)變得極大。MAPE 適合實(shí)際值整體遠(yuǎn)大于 0 的業(yè)務(wù)對斷貨、停業(yè)、尾貨清倉這類場景完全不適用。解決改用 SMAPE對稱平均絕對百分比誤差或 WMAPE。SMAPE 的分母是實(shí)際值和預(yù)測值的均值避免了除零問題。WMAPE 則用誤差絕對值除以所有實(shí)際值的絕對值之和從總量層面衡量相對誤差更貼近業(yè)務(wù)損益。報(bào)告中同時(shí)給出 RMSE 和 WMAPE不單獨(dú)看 MAPE。6. 進(jìn)階技巧用殘差校準(zhǔn)預(yù)測閾值給業(yè)務(wù)一個(gè)可執(zhí)行的數(shù)字模型輸出的預(yù)測值是一個(gè)期望值業(yè)務(wù)方需要的卻往往是一個(gè)區(qū)間安全庫存怎么設(shè)、補(bǔ)貨點(diǎn)怎么定、預(yù)算的下限和上限是多少。這時(shí)候殘差分析就派上用場了。我通常會(huì)在每次重訓(xùn)后計(jì)算測試集殘差實(shí)際值減預(yù)測值的標(biāo)準(zhǔn)差然后以預(yù)測值為中心給出置信區(qū)間。對于銷量這類波動(dòng)較大的數(shù)據(jù)預(yù)測值加減 1.5 倍殘差標(biāo)準(zhǔn)差覆蓋絕大多數(shù)真實(shí)情況。這里有個(gè)關(guān)鍵參數(shù)置信系數(shù)不要定死我一般取 1.28、1.5、1.96 三檔分別對應(yīng) 80%、85%、95% 覆蓋區(qū)間的約略值讓業(yè)務(wù)方自己選激進(jìn)還是保守。殘差分析的另一個(gè)用法是檢測模型漂移。在生產(chǎn)環(huán)境里實(shí)時(shí)收集預(yù)測值和實(shí)際值計(jì)算滾動(dòng)殘差均值。如果殘差均值持續(xù)偏離 0 超過 3 天說明模型已經(jīng)跟不上最近的數(shù)據(jù)模式需要觸發(fā)重訓(xùn)。我在本地腳本里會(huì)用最后 7 天的滾動(dòng)殘差作為監(jiān)控指標(biāo)超過閾值就打印重訓(xùn)提醒。我的個(gè)人習(xí)慣是在預(yù)測模塊主入口留一個(gè)“預(yù)測不確定性”的開關(guān)默認(rèn)關(guān)閉。只有業(yè)務(wù)方明確需要區(qū)間輸出時(shí)才開啟避免每個(gè)人都被龐大的輸出格式干擾。這個(gè)開關(guān)實(shí)現(xiàn)起來很簡單就是是否計(jì)算殘差標(biāo)準(zhǔn)差的分支邏輯但它在跨部門協(xié)作時(shí)能省掉很多解釋成本。預(yù)測算法沒有銀彈核心是讓代碼結(jié)構(gòu)足夠簡單、參數(shù)邊界足夠清晰、重訓(xùn)路徑足夠自動(dòng)。希望這份 Python 核心預(yù)測的落地筆記能幫你少走幾趟彎路早日把一個(gè)能持續(xù)迭代的預(yù)測模塊跑起來。本文還有配套的精品資源點(diǎn)擊獲取