戰(zhàn):從環(huán)境配置到算法調(diào)優(yōu)的避坑指南)
簡(jiǎn)介《美賽各題型常見(jiàn)參考代碼匯總.zip》是一套面向數(shù)學(xué)建模競(jìng)賽選手的代碼與案例資源包覆蓋從線性回歸、數(shù)據(jù)擬合等基礎(chǔ)統(tǒng)計(jì)方法到遺傳算法改進(jìn)神經(jīng)網(wǎng)絡(luò)等智能優(yōu)化算法適合美賽、國(guó)賽及各類數(shù)學(xué)建模實(shí)戰(zhàn)場(chǎng)景。壓縮包共2000個(gè)文件以bmp圖像、m腳本、mat數(shù)據(jù)、txt說(shuō)明、fig圖表為主要類型混合了源碼、可視化結(jié)果、訓(xùn)練樣例與輔助說(shuō)明便于對(duì)照運(yùn)行或二次改造整體大小約109.72MB。資源目前已有4062人學(xué)習(xí)下載內(nèi)容圍繞常見(jiàn)題型組織包含基礎(chǔ)模型完整示例、改進(jìn)算法多種實(shí)現(xiàn)以及配套的圖形文件和說(shuō)明文檔。讀者可按圖索驥快速定位所需的建模模塊理解算法設(shè)計(jì)與數(shù)據(jù)流并直接復(fù)用或改造代碼特別適合希望系統(tǒng)提升建模實(shí)戰(zhàn)能力、從入門走向進(jìn)階的競(jìng)賽選手。1. 美賽各題型常見(jiàn)參考代碼匯總這份 zip 不是資料庫(kù)是改裝件“美賽各題型常見(jiàn)參考代碼匯總”這類資源下載過(guò)的人不少真正在賽前跑通過(guò)的人不多。整個(gè) zip 的價(jià)值不在于“里面有什么算法”而在于把連續(xù)、離散、優(yōu)化、評(píng)價(jià)、預(yù)測(cè)這幾類題型的常用代碼按參考形態(tài)收在一處數(shù)據(jù)分析、智能算法、神經(jīng)網(wǎng)絡(luò)三個(gè)方向都有對(duì)應(yīng)腳本。它解決的不是“不會(huì)建?!倍恰坝兴悸返珌?lái)不及把代碼跑通”。適合時(shí)間緊、需要先有一份能跑通的基線模型再迭代的隊(duì)伍。我的建議是把它當(dāng)改裝件用先不改算法只換數(shù)據(jù)和目標(biāo)函數(shù)確認(rèn)輸出能做成一頁(yè)圖表再往下調(diào)參數(shù)。2. 打開壓縮包先不急著跑目錄、環(huán)境和數(shù)據(jù)路徑一次理順2.1 目錄結(jié)構(gòu)與文件類型先分清參考代碼、樣例數(shù)據(jù)和說(shuō)明文檔大多數(shù)情況下解壓出來(lái)的內(nèi)容不是一個(gè)大亂燉而是按題型分好的文件夾。以我拆過(guò)的類似資源為例通常會(huì)有 01_連續(xù)型、02_離散型、03_優(yōu)化類這類目錄每個(gè)目錄里放著參考代碼.py 或 .m、示例數(shù)據(jù).csv 或 .xlsx以及一個(gè)說(shuō)明文檔。有些包還會(huì)把繪圖腳本單獨(dú)放一個(gè)文件夾避免主程序和畫圖混在一起。拿到壓縮包第一步是不要在 IDE 里直接點(diǎn)運(yùn)行而是先看一遍目錄。我習(xí)慣先敲一句tree -L 2 -F這樣能在一屏內(nèi)看清哪個(gè)文件是入口、哪個(gè)文件是數(shù)據(jù)。如果系統(tǒng)沒(méi)有 treeWindows 下可以用dir /s /b代替。說(shuō)明文檔可能叫“00_使用說(shuō)明.txt”或 README多數(shù)整理者會(huì)寫清每個(gè)腳本的作用、運(yùn)行前要裝什么庫(kù)、數(shù)據(jù)文件放在哪。重點(diǎn)看三件事。腳本末尾是否有if __name__ __main__:有這一行說(shuō)明可以單獨(dú)運(yùn)行。是否有硬編碼的絕對(duì)路徑。是否引用了相對(duì)路徑下的數(shù)據(jù)文件。參考代碼和樣例數(shù)據(jù)放在同一級(jí)目錄是最理想的因?yàn)榇a大多按相對(duì)路徑讀數(shù)據(jù)。如果說(shuō)明里寫了“請(qǐng)將數(shù)據(jù)放到 data 文件夾”最好原樣保留目錄結(jié)構(gòu)不要為了整潔亂挪文件。挪完以后再跑大概率報(bào) FileNotFoundError這是第一腳踩坑的常見(jiàn)來(lái)源。我一般還會(huì)在解壓后先做一次完整性檢查不是驗(yàn)算數(shù)據(jù)而是確認(rèn) zip 本身沒(méi)壞。如果解壓時(shí)遇到 invalid zip archive、could not find EOCD 這類報(bào)錯(cuò)通常是文件沒(méi)下完整重新下一遍比折騰解壓工具更快。確認(rèn)沒(méi)問(wèn)題后再把“參考代碼”整目錄復(fù)制一份作為工作副本不在原始文件上改。復(fù)制工作副本花不了兩分鐘但能在后續(xù)反復(fù)改參數(shù)時(shí)提供一張后悔藥。2.2 Python 環(huán)境與依賴用 venv 隔離避免“在我機(jī)器上能跑”參考代碼最怕的不是程序本身難而是環(huán)境不一致。很多代碼是 Python 3.6 ~ 3.9 時(shí)代寫的現(xiàn)在用 3.12 直接打開可能連 numpy 都進(jìn)不去。我一般會(huì)為這類資源單獨(dú)建一個(gè)虛擬環(huán)境不讓它污染平時(shí)做項(xiàng)目的主環(huán)境。python -m venv venv source venv/bin/activate pip install --upgrade pip pip install -r requirements.txtWindows 下激活命令換成venv\Scripts\activate。如果壓縮包里沒(méi)有 requirements.txt先用最小依賴集跑通主程序pip install numpy pandas scipy matplotlib scikit-learn解釋一下venv創(chuàng)建的是獨(dú)立環(huán)境包版本不會(huì)互相覆蓋升級(jí) pip 是因?yàn)榕f版 pip 解析復(fù)雜依賴時(shí)容易失敗requirements.txt 里如果寫著 numpy1.19.5 這種老版本先別急著照單全收等主程序跑起來(lái)以后再?zèng)Q定要不要降級(jí)。注意tensorflow 和 keras 相關(guān)的代碼不要一上來(lái)就裝。參考代碼里如果只是用多層感知機(jī)scikit-learn 就夠。確實(shí)要用 LSTM 再單獨(dú)裝 tensorflowCPU 版在賽題數(shù)據(jù)量下也足夠不需要一開始就折騰 GPU。裝完以后做一個(gè)最小驗(yàn)證python -c import numpy, pandas, sklearn; print(ok)這一句能快速排除“環(huán)境白裝了”的情況。還有一類坑藏在依賴約束里如果 requirements 里寫著 tensorflow2.10在老機(jī)器上會(huì)因?yàn)?CPU 指令集問(wèn)題裝不上。遇到這種情況常見(jiàn)做法是改用 conda 裝讓 conda 挑一個(gè)與當(dāng)前硬件匹配的包。如果還不行就用 CPU 版代替代價(jià)只是訓(xùn)練慢一點(diǎn)不影響正確性。部分包里的 .m 文件是 MATLAB 代碼Python 環(huán)境管不了它們先跳過(guò)4.3 會(huì)講替代路線。2.3 數(shù)據(jù)路徑約定為什么相對(duì)路徑比絕對(duì)路徑靠譜參考代碼里常見(jiàn)兩種讀數(shù)據(jù)方式一種是寫死pd.read_excel(C:/Users/xxx/data.xlsx)一種是os.path.join(os.getcwd(), data)拼路徑。前者換臺(tái)電腦就廢后者換啟動(dòng)目錄就廢。自己改的時(shí)候我一般統(tǒng)一換成基于當(dāng)前腳本文件算路徑的方案from pathlib import Path # 當(dāng)前腳本所在目錄不是命令行所在目錄 BASE_DIR Path(__file__).resolve().parent data_path BASE_DIR / data / data.csv df pd.read_csv(data_path, encodingutf-8) print(路徑檢查:, data_path, 存在:, data_path.exists())邏輯說(shuō)明__file__是當(dāng)前文件的路徑resolve()把相對(duì)路徑轉(zhuǎn)成絕對(duì)路徑parent取上一級(jí)目錄再往下拼數(shù)據(jù)文件。這樣不管 zip 解壓到哪個(gè)位置只要內(nèi)部目錄結(jié)構(gòu)不變代碼就能找到數(shù)據(jù)。打印路徑和exists()是為了在找不到文件時(shí)立刻看到實(shí)際指向。我還會(huì)在開頭加一個(gè)檢查路徑不存在就打印提示并返回。很多參考代碼翻車不是算法問(wèn)題而是數(shù)據(jù)沒(méi)讀進(jìn)來(lái)后面所有矩陣都是空。路徑問(wèn)題一次理順能省掉一整天的排查時(shí)間。還要多一句嘴盡量把 Excel 轉(zhuǎn)成 CSV 再喂給 pandas。Excel 讀取本身沒(méi)問(wèn)題但多行表頭、合并單元格、日期格式都會(huì)在讀入時(shí)產(chǎn)生意外CSV 沒(méi)有這些花樣出問(wèn)題也好查。如果代碼讀的是 xlsx而你的數(shù)據(jù)在多個(gè) sheet 里最簡(jiǎn)單的處理是先把目標(biāo) sheet 另存為 CSV再改路徑。不要在參考代碼上做太多自由度很高的改動(dòng)改動(dòng)越多邊界越難查。3. 把題型和代碼模板對(duì)上先判斷它到底該用哪份參考代碼3.1 題型分類與算法選型一張表說(shuō)明映射關(guān)系美賽題型從建模角度大致分成五類連續(xù)、離散、優(yōu)化、評(píng)價(jià)、預(yù)測(cè)。參考代碼包通常是按這個(gè)分類組織的。拿到題目以后先判斷題型再找對(duì)應(yīng)參考代碼順序不要反過(guò)來(lái)。題型常見(jiàn)背景默認(rèn)參考算法包里對(duì)應(yīng)方向連續(xù)型物理變化、增長(zhǎng)曲線、流量趨勢(shì)微分方程 插值擬合01_連續(xù)型離散型網(wǎng)絡(luò)、狀態(tài)轉(zhuǎn)移、排隊(duì)圖論最短路/流、狀態(tài)轉(zhuǎn)移矩陣02_離散型優(yōu)化類資源分配、路徑規(guī)劃、生產(chǎn)調(diào)度遺傳算法、粒子群、模擬退火03_優(yōu)化評(píng)價(jià)類方案比選、風(fēng)險(xiǎn)排序、多指標(biāo)評(píng)分熵權(quán)法、TOPSIS、層次分析04_評(píng)價(jià)預(yù)測(cè)類未來(lái)趨勢(shì)、回歸、時(shí)序線性回歸、MLP、LSTM05_預(yù)測(cè)選型邏輯很簡(jiǎn)單。連續(xù)型題目給的是變化過(guò)程要找函數(shù)關(guān)系優(yōu)先擬合和參數(shù)估計(jì)。離散型題目涉及狀態(tài)和路徑圖論模型更直接。優(yōu)化類題目如果變量少、約束簡(jiǎn)單窮舉或線性規(guī)劃就行變量一多啟發(fā)式算法更現(xiàn)實(shí)。評(píng)價(jià)類題目沒(méi)有標(biāo)準(zhǔn)答案關(guān)鍵是權(quán)重怎么來(lái)熵權(quán)法屬于數(shù)據(jù)驅(qū)動(dòng)比拍腦袋定權(quán)重有說(shuō)服力。預(yù)測(cè)類題目要的是未來(lái)值先跑一個(gè)簡(jiǎn)單回歸當(dāng)基線再看要不要上神經(jīng)網(wǎng)絡(luò)??磪⒖即a時(shí)不要上來(lái)就挑最“高級(jí)”的算法。對(duì)一場(chǎng)三到四天的比賽而言能跑通、能穩(wěn)定復(fù)現(xiàn)結(jié)果的基線遠(yuǎn)比一個(gè)只在理想例子上好看的高級(jí)模型重要。假如題目還沒(méi)審?fù)昃痛蜷_ LSTM 腳本復(fù)制粘貼后續(xù)只會(huì)花大量時(shí)間在調(diào)參而不是解題上。參考代碼包的意義是提供起點(diǎn)不是終點(diǎn)。我一般會(huì)把“能找到基線結(jié)果”作為第一目標(biāo)確認(rèn)它能輸出圖表和指標(biāo)再談優(yōu)化。3.2 智能算法參考代碼遺傳算法怎么改適應(yīng)度函數(shù)優(yōu)化類題目對(duì)應(yīng)的智能算法多數(shù)是基于種群的啟發(fā)式搜索。壓縮包里這類代碼的結(jié)構(gòu)大同小異一個(gè)主函數(shù)負(fù)責(zé)初始化種群和迭代一個(gè)適應(yīng)度函數(shù)負(fù)責(zé)評(píng)價(jià)個(gè)體。真正需要你改的只有適應(yīng)度函數(shù)其他部分幾乎不用動(dòng)。下面這段是能直接跑的簡(jiǎn)化框架import numpy as np def fitness(x): # 以最小化 f x^2 2 為例 return x[0] ** 2 2 def ga(fn, lb-10.0, ub10.0, pop_size50, max_gen100, pc0.8, pm0.05): dim 1 pop np.random.uniform(lb, ub, (pop_size, dim)) for g in range(max_gen): scores np.array([fn(ind) for ind in pop]) order np.argsort(scores) pop pop[order] new_pop [pop[0].copy()] # 精英保留 while len(new_pop) pop_size: # 錦標(biāo)賽只從前一半隨機(jī)取兩個(gè) a pop[np.random.randint(0, pop_size // 2)] b pop[np.random.randint(0, pop_size // 2)] # 算術(shù)交叉 child 0.5 * (a b) if np.random.rand() pc else a.copy() # 高斯變異 if np.random.rand() pm: child np.clip(child np.random.normal( 0, 0.5 * (ub - lb)), lb, ub) new_pop.append(child) pop np.array(new_pop) idx int(np.argmin([fn(ind) for ind in pop])) return pop[idx], fn(pop[idx]) best, val ga(fitness) print(最優(yōu)解:, best, 最優(yōu)值:, val)邏輯說(shuō)明初始化階段用均勻分布在上下界之間生成種群。每輪迭代先按適應(yīng)度排序適應(yīng)度越小排名越靠前錦標(biāo)賽機(jī)制只從排序前一半個(gè)體里隨機(jī)取兩個(gè)做交叉保證優(yōu)質(zhì)個(gè)體更容易被選中精英保留策略把上一代最優(yōu)解直接復(fù)制進(jìn)下一代防止最優(yōu)解丟失。變異用高斯擾動(dòng)np.clip把子代限制在邊界內(nèi)。代碼以最小化問(wèn)題為例如果賽題是最大化收益在適應(yīng)度函數(shù)里加個(gè)負(fù)號(hào)即可。參數(shù)說(shuō)明pop_size是種群規(guī)模一般取 30~200越大收斂越穩(wěn)但越慢max_gen是迭代代數(shù)建議從 100 開始看收斂曲線不夠再加pc是交叉概率0.6~0.9 是常見(jiàn)區(qū)間pm是變異概率太小容易早熟太大退化成隨機(jī)搜索0.05~0.2 可以先用。邊界lb和ub要跟決策變量的物理含義走比如資源分配問(wèn)題里變量不能為負(fù)lb就設(shè)為 0。改適應(yīng)度函數(shù)時(shí)最常犯的錯(cuò)誤是把賽題里的幾個(gè)目標(biāo)直接塞進(jìn)一個(gè)返回值而不考慮量綱。既要成本最小又要時(shí)間最短直接相加會(huì)讓數(shù)值大的那項(xiàng)主導(dǎo)搜索。常見(jiàn)做法是先歸一化再加權(quán)把原始目標(biāo)分別除以各自的最大值再乘權(quán)重相加。參考代碼里只留了一個(gè)適應(yīng)度函數(shù)入口的話你的工作量就集中在這一處。3.3 神經(jīng)網(wǎng)絡(luò)參考代碼從 MLP 到 LSTM 的兩級(jí)方案預(yù)測(cè)類代碼一般分兩類同一時(shí)刻輸入輸出用 MLP按時(shí)間先后輸入輸出用 LSTM。很多參考代碼包會(huì)把兩層都放進(jìn)去但先別急著用深度學(xué)習(xí)。先用 MLP 建立基線跑通了再換 LSTM這個(gè)順序能避免陷入黑匣子調(diào)參的泥潭。下面是 MLP 參考代碼的常見(jiàn)形態(tài)import numpy as np import pandas as pd from sklearn.neural_network import MLPRegressor from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler df pd.read_csv(data/train.csv) X df.iloc[:, :-1].values y df.iloc[:, -1].values X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42) scaler StandardScaler() X_train scaler.fit_transform(X_train) X_test scaler.transform(X_test) model MLPRegressor( hidden_layer_sizes(64, 32), activationrelu, max_iter500, random_state0 ) model.fit(X_train, y_train) print(train R2:, model.score(X_train, y_train)) print(test R2:, model.score(X_test, y_test))邏輯說(shuō)明df.iloc[:, :-1]取所有行除最后一列默認(rèn)最后一列是標(biāo)簽train_test_split按八二劃分StandardScaler先 fit 再 transform測(cè)試集只做 transform不做 fit。這個(gè)順序是為了防止信息泄漏如果測(cè)試集也參與計(jì)算均值方差相當(dāng)于把測(cè)試集信息暴露給模型。model.score在回歸問(wèn)題里輸出的是 R2越接近 1 越好。參數(shù)說(shuō)明hidden_layer_sizes(64, 32)表示兩個(gè)隱藏層神經(jīng)元數(shù)分別 64 和 32。層數(shù)和神經(jīng)元數(shù)不是越大越好賽題數(shù)據(jù)通常只有幾千行兩層 32~64 足夠。max_iter是最大迭代次數(shù)如果訓(xùn)練還沒(méi)收斂就停了會(huì)看到警告調(diào)大到 800。activation保持 relu除非有特殊理由。random_state0保證每次跑的結(jié)果一致。時(shí)序類題目再用 LSTM。參考代碼里常見(jiàn)的是這種構(gòu)造窗口的寫法import numpy as np def build_sequences(x, look_back10): Xs, ys [], [] for i in range(len(x) - look_back): Xs.append(x[i:i look_back]) ys.append(x[i look_back]) return np.array(Xs), np.array(ys) # 數(shù)據(jù)一維窗口 10 步 data np.loadtxt(data/series.csv) X, y build_sequences(data, 10) # LSTM 輸入要求 (樣本數(shù), 時(shí)間步, 特征數(shù)) X X.reshape(X.shape[0], X.shape[1], 1) print(X.shape, y.shape)邏輯說(shuō)明look_back決定用過(guò)去多少步預(yù)測(cè)下一步Xs里每個(gè)元素是一個(gè)長(zhǎng)度為窗口的片段ys是對(duì)應(yīng)的下一個(gè)值。最后一定要把二維輸入 reshape 成三維第三維是特征數(shù)。這是 LSTM 參考代碼里最常見(jiàn)的結(jié)構(gòu)門檻。這里有個(gè)容易翻車的細(xì)節(jié)時(shí)序數(shù)據(jù)生成序列時(shí)不能隨機(jī)打亂否則時(shí)間順序就沒(méi)了。MLP 那一步可以用train_test_splitLSTM 這步只能按時(shí)間前后切分。參考代碼里如果用random.shuffle處理時(shí)序數(shù)據(jù)說(shuō)明它只適合做回歸示例不能直接套到趨勢(shì)預(yù)測(cè)上。壓縮包里如果給的是 LSTM 腳本先檢查它的數(shù)據(jù)預(yù)處理里有沒(méi)有打亂時(shí)序再?zèng)Q定要不要用。4. 避坑參考代碼運(yùn)行時(shí)的五個(gè)典型坑與排查順序4.1 中文路徑和 Excel 編碼導(dǎo)致的讀取失敗現(xiàn)象pd.read_csv(數(shù)據(jù).csv)直接報(bào) UnicodeDecodeError或者報(bào) FileNotFoundError但文件明明在。這兩種報(bào)錯(cuò)都讓人很煩躁因?yàn)閱?wèn)題不在代碼邏輯而在文件本身。原因Windows 下很多 Excel 另存的 CSV 是 GBK 或 GB2312 編碼而 pandas 默認(rèn)用 UTF-8 讀路徑里的中文還可能被腳本當(dāng)作亂碼處理。參考代碼通常是整理者在自己電腦上跑通的他可能從來(lái)沒(méi)遇到過(guò)編碼問(wèn)題。解決讀取時(shí)指定編碼或者加一次兜底重試。try: df pd.read_csv(path, encodingutf-8) except UnicodeDecodeError: df pd.read_csv(path, encodinggbk)邏輯說(shuō)明先按 UTF-8 讀讀不了再退回 GBK。這套邏輯能覆蓋絕大多數(shù)從中文 Excel 導(dǎo)出的 CSV。如果兩種編碼都失敗直接用文本編輯器把 CSV 另存為帶 BOM 的 UTF-8是最省事的方案。路徑里有中文導(dǎo)致的 FileNotFoundError比編碼問(wèn)題更隱蔽排查時(shí)先打印os.path.abspath(path)看實(shí)際路徑再檢查文件名里的全角字符。4.2 NumPy 語(yǔ)法差異老代碼在新環(huán)境里報(bào)錯(cuò)的替換寫法現(xiàn)象代碼里np.bool、np.float直接報(bào) AttributeError或者程序停在一句類型判斷上提示 module numpy has no attribute xxx。原因參考代碼大多寫于 NumPy 1.24 發(fā)布之前老版本把np.float這類別名暴露在命名空間里新版本把它們刪掉了。參考代碼整理者通常不會(huì)為每個(gè)腳本做版本適配這類問(wèn)題只能自己動(dòng)手。解決把下面這個(gè)表記在心里遇到什么換什么。老寫法新寫法np.boolbool 或 np.bool_np.floatfloat 或 np.float64np.intint 或 np.int64np.objectobject替換完大多數(shù)情況就能跑。還有 pandas 的df.append在 2.0 里被移除老代碼如果用一句df df.append(new_row)會(huì)報(bào)屬性缺失改成pd.concat([df, new_row], ignore_indexTrue)。這些改動(dòng)屬于機(jī)械替換不算改業(yè)務(wù)邏輯。如果替換完還報(bào)錯(cuò)優(yōu)先看報(bào)錯(cuò)堆棧最下面一行那才是真正出問(wèn)題的地方不要在 warnings 里找原因。4.3 MATLAB 方案在沒(méi)裝 MATLAB 的機(jī)器上的替代路線現(xiàn)象.m文件雙擊打不開或者好不容易裝了個(gè)環(huán)境發(fā)現(xiàn)腳本用到某些工具箱函數(shù)報(bào)“函數(shù)未定義”。原因壓縮包里的部分參考代碼是 MATLAB 工作流寫的依賴統(tǒng)計(jì)工具箱或優(yōu)化工具箱而多數(shù)隊(duì)伍沒(méi)有正版授權(quán)網(wǎng)上找的替代品又容易在版本上出問(wèn)題。解決用 Octave 跑大部分.m文件或者在包里找對(duì)應(yīng)的 Python 實(shí)現(xiàn)。octave-cli model.m如果 Octave 報(bào)某個(gè)函數(shù)不存在八成是fitnlm、ga這類工具箱函數(shù)。處理辦法有兩個(gè)一是手動(dòng)把這個(gè)函數(shù)翻譯成 scipy.optimize 里對(duì)應(yīng)的接口二是直接放棄這批 MATLAB 代碼改用包里的 Python 版本。我的習(xí)慣是優(yōu)先找 Python 版本比賽時(shí)沒(méi)有時(shí)間花在翻譯語(yǔ)法上。還要注意一點(diǎn)MATLAB 和 Python 混在同一個(gè)文件夾時(shí)data.mat和data.csv可能同時(shí)存在腳本讀的未必是你以為的那個(gè)文件。跑之前看一眼代碼里的文件名不要想當(dāng)然。4.4 矩陣維度與數(shù)據(jù)順序shape 不一致比報(bào)錯(cuò)更隱蔽現(xiàn)象程序不報(bào)錯(cuò)結(jié)果卻很奇怪比如所有預(yù)測(cè)值都接近同一常數(shù)或者優(yōu)化結(jié)果明顯偏離常識(shí)。這類問(wèn)題最難查因?yàn)殄e(cuò)誤不會(huì)直接彈出來(lái)。原因最常見(jiàn)的是標(biāo)簽和特征列順序不對(duì)、X 和 y 行數(shù)不一致、Excel 表頭被讀成一行數(shù)據(jù)。這三個(gè)問(wèn)題都會(huì)讓模型在錯(cuò)誤維度上訓(xùn)練。解決在訓(xùn)練前強(qiáng)制打印并斷言關(guān)鍵數(shù)據(jù)的形狀。print(X shape:, X.shape, y shape:, y.shape) assert len(X) len(y) assert X.shape[0] 1如果 X 是二維(n, 1)而算法要求(n, m)模型有可能把一個(gè)特征當(dāng)多特征用數(shù)值上不報(bào)錯(cuò)但預(yù)測(cè)結(jié)果會(huì)集中在均值附近。原因在于每個(gè)樣本攜帶的信息太少模型只能學(xué)到標(biāo)簽均值。查法是這樣把特征名打印出來(lái)確認(rèn)第一列不是序號(hào)再把第一行打印出來(lái)確認(rèn)沒(méi)混入表頭。還要注意數(shù)據(jù)順序預(yù)測(cè)類題目按天給數(shù)據(jù)如果用隨機(jī)打亂的方式劃分訓(xùn)練集和驗(yàn)證集時(shí)間規(guī)律會(huì)被打散。參考代碼里如果帶了 shuffle要格外小心。時(shí)序數(shù)據(jù)只能按時(shí)間切分先看有沒(méi)有時(shí)間列有就按時(shí)間排序后再切。我見(jiàn)過(guò)有人把訓(xùn)練集和驗(yàn)證集混在一起標(biāo)準(zhǔn)化結(jié)果驗(yàn)證時(shí)指標(biāo)很好看提交后發(fā)現(xiàn)完全不可用這就是信息泄漏屬于數(shù)據(jù)順序問(wèn)題里最傷的一種。4.5 隨機(jī)種子與結(jié)果復(fù)現(xiàn)為什么第二次跑結(jié)果不一樣現(xiàn)象同一份代碼第一次跑出 R20.83第二次變成 0.79遺傳算法兩次最優(yōu)解完全不同。很多隊(duì)伍在結(jié)果里寫“模型 R2 為 0.83”實(shí)際上這個(gè)數(shù)字根本不可復(fù)現(xiàn)。原因參考代碼沒(méi)有固定隨機(jī)種子初始化、劃分、變異都受隨機(jī)數(shù)影響。嚴(yán)格來(lái)說(shuō)不可復(fù)現(xiàn)的結(jié)果不能作為論證依據(jù)。解決程序入口處固定種子。import random import numpy as np random.seed(0) np.random.seed(0) # sklearn 內(nèi)部還在 random_state 參數(shù)里固定 # tensorflow/keras 固定方式不同 import tensorflow as tf tf.random.set_seed(0)說(shuō)明Python 標(biāo)準(zhǔn)庫(kù)random影響部分腳本numpy 影響大部分科學(xué)計(jì)算sklearn 基本靠random_state參數(shù)tensorflow 要單獨(dú)設(shè)種子。只固定一處不夠三處都要固定。固定種子以后前后兩次結(jié)果一致才能放心比較參數(shù)。如果固定完還是有浮動(dòng)檢查代碼里有沒(méi)有在循環(huán)里調(diào)用np.random且沒(méi)有走同一個(gè)種子分支。5. 從參考代碼到自己的模型文件賽前 48 小時(shí)的驗(yàn)證流程5.1 用一道舊題把四個(gè)模板跑通拿到參考代碼后最有效的第一個(gè)動(dòng)作不是讀代碼而是找一道往年賽題把連續(xù)、優(yōu)化、預(yù)測(cè)三個(gè)模板分別套一次。目標(biāo)不是得高分而是確認(rèn)每個(gè)腳本都能輸入、運(yùn)行、輸出結(jié)果。我會(huì)記錄每個(gè)腳本的運(yùn)行時(shí)間超過(guò)十分鐘的算法文件先縮小數(shù)據(jù)規(guī)模跑通再?zèng)Q定要不要全量跑。這個(gè)預(yù)跑過(guò)程相當(dāng)于給后面的比賽上保險(xiǎn)。5.2 參數(shù)掃描參考代碼不夠好就調(diào)這些旋鈕跑通基線后不要再憑感覺(jué)調(diào)參直接做一個(gè)小網(wǎng)格搜索results [] for lr in [0.01, 0.001]: for hidden in [(32,), (64, 32)]: model MLPRegressor( hidden_layer_sizeshidden, learning_rate_initlr, max_iter500, random_state0 ) model.fit(X_train, y_train) results.append((lr, hidden, model.score(X_test, y_test))) for r in sorted(results, keylambda t: -t[2]): print(r)邏輯說(shuō)明兩層循環(huán)遍歷學(xué)習(xí)率和隱藏層結(jié)構(gòu)把每組參數(shù)對(duì)應(yīng)的測(cè)試集 R2 記錄下來(lái)最后按從高到低排序。這樣選參數(shù)是有依據(jù)的而不是靠“感覺(jué)上次跑得好”。注意固定random_state0否則不同參數(shù)組之間的差異會(huì)被隨機(jī)噪聲干擾。如果參考代碼里已經(jīng)有 main 函數(shù)把它改造成接受參數(shù)的版本能省不少事。最后對(duì)每個(gè)提交結(jié)果做一次輸出檢查圖有沒(méi)有數(shù)據(jù)、坐標(biāo)軸有沒(méi)有標(biāo)簽、單位有沒(méi)有寫、參數(shù)表是不是和正文一致。有一次我為了趕時(shí)間把訓(xùn)練集和驗(yàn)證集一起標(biāo)準(zhǔn)化驗(yàn)證集結(jié)果非常好看提交后才發(fā)現(xiàn)信息泄漏后悔藥都沒(méi)地方買。從那以后我每次跑參考代碼都強(qiáng)制走一遍固定種子、標(biāo)準(zhǔn)化只對(duì)訓(xùn)練集 fit、結(jié)果先復(fù)現(xiàn)再提指標(biāo)這三步。希望這套流程能幫到你。本文還有配套的精品資源點(diǎn)擊獲取