器學(xué)習(xí)大作業(yè)高分攻略:選題、代碼與實(shí)驗(yàn)報(bào)告全指南)
簡介這是一份面向高校機(jī)器學(xué)習(xí)課程期末大作業(yè)與課程設(shè)計(jì)的高分項(xiàng)目合集包含多組可運(yùn)行的Python源碼與配套實(shí)驗(yàn)報(bào)告覆蓋決策樹、聚類、回歸、分類等常見實(shí)驗(yàn)題目代碼中帶有詳細(xì)注釋新手也能讀懂并快速部署使用。壓縮包整體約2.94MB共15個(gè)文件其中10個(gè)py文件為核心實(shí)現(xiàn)腳本2個(gè)csv為實(shí)驗(yàn)數(shù)據(jù)另含txt說明、data數(shù)據(jù)文件及docx格式的實(shí)驗(yàn)報(bào)告結(jié)構(gòu)清晰便于按章節(jié)或題號查閱。當(dāng)前已有382人瀏覽學(xué)習(xí)適合需要參考完整思路、完成課程作業(yè)或提升項(xiàng)目實(shí)踐能力的學(xué)生使用。資源源自西安電子科技大學(xué)機(jī)器學(xué)習(xí)大作業(yè)實(shí)驗(yàn)報(bào)告與代碼一一對應(yīng)詳細(xì)注釋覆蓋數(shù)據(jù)讀取、模型訓(xùn)練和結(jié)果可視化等關(guān)鍵環(huán)節(jié)。整體功能完整、界面簡潔可直接作為期末提交或課程設(shè)計(jì)的優(yōu)質(zhì)模板。1. 機(jī)器學(xué)習(xí)大作業(yè)拿高分先搞清楚評審在找什么機(jī)器學(xué)習(xí)大作業(yè)不像期末考試沒有標(biāo)準(zhǔn)答案評分盯的是流程完整度、結(jié)果可信度和報(bào)告解釋力。所謂“項(xiàng)目合集”就是把你交的東西拆成三份選對題目、寫好代碼、把報(bào)告做成能照著復(fù)現(xiàn)的實(shí)驗(yàn)冊子。高分項(xiàng)目往往不是模型最深的那個(gè)而是每步都有據(jù)可查的那個(gè)。很多人把時(shí)間全砸在調(diào)參上最后卻栽在報(bào)告沒有對比基線、代碼換臺機(jī)器就跑不動(dòng)。這篇文章就按沖高分的路線把項(xiàng)目選題、代碼規(guī)范、實(shí)驗(yàn)報(bào)告和常見扣分點(diǎn)一次講清楚適合想拿高分、或想把課程項(xiàng)目收進(jìn)簡歷的讀者。2. 高分項(xiàng)目怎么選題與搭基線三類必做項(xiàng)目與數(shù)據(jù)選型選對題是投入產(chǎn)出比最高的一步。機(jī)器學(xué)習(xí)的應(yīng)用流程其實(shí)就是數(shù)據(jù)理解、建模、評估、解釋四步課程大作業(yè)不管寫成什么樣評審都在這四步上找分?jǐn)?shù)。常見大作業(yè)能歸成幾類表格分類、回歸與時(shí)序預(yù)測、聚類降維再往外一點(diǎn)還有文本分類和圖像分類。但課程時(shí)間有限評審更在意“把一個(gè)題做完整”而不是“同時(shí)開三個(gè)題全部爛尾”。所以我一般把“項(xiàng)目合集”當(dāng)成一個(gè)項(xiàng)目庫來用先按難度和興趣各挑兩三個(gè)候選題再用三條標(biāo)準(zhǔn)過濾數(shù)據(jù)能不能輕松拿到、baseline 能不能半小時(shí)內(nèi)跑通、題目有沒有可解釋空間。三條都滿足才值得往下走。2.1 分類題從結(jié)構(gòu)化數(shù)據(jù)到圖像先定難度階梯最常見也最穩(wěn)妥的是結(jié)構(gòu)化表格分類這類題數(shù)據(jù)量小、訓(xùn)練快特別適合撐起“數(shù)據(jù)清洗 特征工程 模型對比”的完整流程。我習(xí)慣把分類題分成三檔。第一檔用 sklearn 內(nèi)置數(shù)據(jù)集比如鳶尾花、乳腺癌、手寫數(shù)字幾分鐘跑完適合只剩一天的情況但缺點(diǎn)是太常見開題容易撞車。第二檔從公開渠道下載真實(shí)業(yè)務(wù)數(shù)據(jù)比如銀行營銷、電信客戶流失、垃圾短信特征是類別不平衡或缺失值嚴(yán)重寫“機(jī)器學(xué)習(xí)中的數(shù)據(jù)處理是什么”這個(gè)環(huán)節(jié)時(shí)就有真實(shí)材料可用。第三檔是 Kaggle 上幾十萬行的大數(shù)據(jù)能寫最豐富但也最容易讓人陷在調(diào)參里出不來作業(yè)反而爛尾。多數(shù)高分項(xiàng)目的位置在“第二檔任務(wù) 認(rèn)真做實(shí)驗(yàn)對比”而不是第三檔。選數(shù)據(jù)時(shí)還有一個(gè)容易忽略的硬件問題如果課程機(jī)房的機(jī)器只有 4GB 內(nèi)存就不要選動(dòng)輒幾百 MB 的特征矩陣。我見過一個(gè)小組選了 Kaggle 上幾十萬行的點(diǎn)擊率預(yù)測數(shù)據(jù)預(yù)處理跑了一個(gè)通宵最后報(bào)告只能寫“由于內(nèi)存不足實(shí)驗(yàn)未完成”這等于直接放棄評分點(diǎn)。圖像分類這邊MNIST 或 CIFAR-10 的子集都是安全選項(xiàng)。如果課程允許 PyTorchMNIST 用 LeNet 半小時(shí)就能訓(xùn)完再用 SVM 做 baseline報(bào)告里就有傳統(tǒng)算法與深度網(wǎng)絡(luò)的完整敘事。下面這個(gè)分類代碼骨架用 load_digits 而不是 MNIST因?yàn)樗谡n堂演示時(shí)加載最快、不依賴外網(wǎng)適合做作業(yè)起點(diǎn)from sklearn.datasets import load_digits from sklearn.model_selection import train_test_split from sklearn.ensemble import RandomForestClassifier from sklearn.metrics import classification_report, confusion_matrix # 加載數(shù)據(jù)先看形狀和類別這一步寫進(jìn)報(bào)告的“數(shù)據(jù)理解” digits load_digits() print(digits.data.shape) # (1797, 64)8x8 圖像展平 print(digits.target_names) # 類別 0-9 # 分層劃分保證訓(xùn)練/測試?yán)飻?shù)字類別比例一致 X, y digits.data, digits.target X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42, stratifyy ) # baseline隨機(jī)森林默認(rèn)參數(shù)先出一個(gè)底線分?jǐn)?shù) rf RandomForestClassifier(random_state42) rf.fit(X_train, y_train) print(test acc:, rf.score(X_test, y_test)) # 輸出混淆矩陣報(bào)告里放這張圖能直接撐起一頁 print(confusion_matrix(y_test, rf.predict(X_test)))這里有兩個(gè)容易出錯(cuò)的操作。train_test_split 的 stratify 參數(shù)表示按類別比例分層劃分如果某個(gè)數(shù)字本身樣本少不做分層就可能出現(xiàn)訓(xùn)練集里有 0 但測試集沒有 0混淆矩陣畫出來缺一行random_state42 讓劃分結(jié)果固定否則每次運(yùn)行訓(xùn)練集都不一樣報(bào)告里的準(zhǔn)確率就成了不可復(fù)現(xiàn)的數(shù)字。RandomForestClassifier(random_state42) 里的隨機(jī)種子最好也固定這棵樹雖然在作業(yè)里只是 baseline但后面所有對比實(shí)驗(yàn)都要以它為準(zhǔn)。baseline 的意義是提供一個(gè)最低參照線之后 SVC、xgboost 這些模型的改進(jìn)幅度全部由它襯托出來。如果你是第一次做這類題建議把代碼按“讀數(shù)據(jù)、劃分、訓(xùn)練、評測”四步組織。讀數(shù)據(jù)段打印 shape 和類別數(shù)量劃分段寫明 test_size 和 random_state訓(xùn)練段用同一個(gè)固定種子評測段輸出準(zhǔn)確率、F1 和混淆矩陣。把四段都寫進(jìn)報(bào)告對應(yīng)的小節(jié)評審不看完整代碼也知道你做了什么。第二個(gè)常被忽略的細(xì)節(jié)是類別分布打印 y_train 的 value_counts如果發(fā)現(xiàn)某一類比另一類多好幾倍報(bào)告里就自然引出一段類別不平衡的討論哪怕只是用 class_weightbalanced 跑一次對比也說明你想到了這個(gè)問題。2.2 回歸與時(shí)序題可解釋性比精度更值錢回歸題里波士頓房價(jià)數(shù)據(jù)集因?yàn)橛忻舾袑傩誀幾h已經(jīng)不適合再作為課程項(xiàng)目常見替代是加州房價(jià)、Kaggle 二手房數(shù)據(jù)或超市銷售額預(yù)測。時(shí)序題里電力負(fù)荷、氣象溫度、電商銷量都比較安全而股票預(yù)測看起來炫酷但對課程作業(yè)是個(gè)坑——股價(jià)噪聲強(qiáng)、特征語義弱老師追問“你的特征依據(jù)是什么”時(shí)很難講清楚。我的選型邏輯是回歸和時(shí)序題優(yōu)先選特征有明確業(yè)務(wù)含義的數(shù)據(jù)因?yàn)檫@類作業(yè)的價(jià)值不在把 RMSE 壓到多低而在你能解釋誤差來自哪里。線性回歸、隨機(jī)森林和 XGBoost 的對比在結(jié)構(gòu)化數(shù)據(jù)上很容易出圖表再配上 SHAP 或 feature_importances_報(bào)告的可信度一下子就能上去。import pandas as pd from sklearn.datasets import fetch_california_housing from sklearn.model_selection import train_test_split from sklearn.ensemble import RandomForestRegressor from sklearn.metrics import mean_squared_error, r2_score housing fetch_california_housing() X, y housing.data, housing.target X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42 ) model RandomForestRegressor(n_estimators100, random_state42) model.fit(X_train, y_train) pred model.predict(X_test) print(RMSE:, mean_squared_error(y_test, pred, squaredFalse)) print(R2:, r2_score(y_test, pred)) # 特征重要性導(dǎo)出成 csv報(bào)告里做成直方圖 importance pd.Series(model.feature_importances_, indexhousing.feature_names) importance.sort_values(ascendingFalse).to_csv(feature_importance.csv)這里的兩個(gè)指標(biāo)要一起看。RMSE 是均方根誤差單位與目標(biāo)一致能說明預(yù)測偏離真實(shí)值多遠(yuǎn)R2 是決定系數(shù)表示模型解釋了目標(biāo)方差的百分比。只放 RMSE 會(huì)被問“這個(gè)數(shù)對業(yè)務(wù)意味著什么”只放 R2 會(huì)被問“離群點(diǎn)是不是被忽略”兩個(gè)都放基本能堵住這兩個(gè)問題。n_estimators100 是隨機(jī)森林的起點(diǎn)作業(yè)數(shù)據(jù)集通常只有幾萬行繼續(xù)加到 300 回報(bào)很小訓(xùn)練時(shí)間卻翻三倍。feature_importance.csv 導(dǎo)出后不要只貼在報(bào)告里最好畫一張排序條形圖并在圖注里寫一句最明顯的結(jié)論比如“MedInc 是預(yù)測房價(jià)最重要的特征”。就算這是常識輸出它說明你做了歸因而不是只會(huì) print 分?jǐn)?shù)。如果題目要求必須用深度學(xué)習(xí)LSTM 是最常被抄的模型。網(wǎng)上“l(fā)stm模型代碼”絕大多數(shù)是股票預(yù)測 demo結(jié)構(gòu)相同換數(shù)據(jù)就能跑但報(bào)告只貼代碼、不寫清輸入窗口長度、預(yù)測步長和損失函數(shù)評審大概率直接判為代跑。用自己的話說清楚一件事就夠了你是如何把原始序列切成滑窗樣本的?;伴L度太長會(huì)讓樣本數(shù)量變少太短則學(xué)不到周期多試幾個(gè)窗口長度做對比報(bào)告里寫“窗口 24 小時(shí)的誤差比窗口 6 小時(shí)低 8%”這段話比模型結(jié)構(gòu)值錢得多。2.3 基線先行sklearn pipeline 必須先跑通大作業(yè)翻車的一個(gè)共性原因是跳過 baseline上手就訓(xùn)練高級模型跑了半天發(fā)現(xiàn)被線性回歸打敗心態(tài)崩了不說報(bào)告也寫不出對比。我一般強(qiáng)制自己的流程是“先讓最樸素模型跑通、打印出指標(biāo)、存下日志再考慮改進(jìn)”。所謂 baseline 不一定是最差模型而是邏輯上最簡單、幾乎不可能出錯(cuò)的方案分類用邏輯回歸或決策樹回歸用線性回歸圖像任務(wù)用原始像素加 SVM。它存在的意義是證明你的數(shù)據(jù)管線沒問題也證明后續(xù)模型的提升不是玄學(xué)。from sklearn.pipeline import Pipeline from sklearn.preprocessing import StandardScaler from sklearn.svm import SVC pipe Pipeline([ (scaler, StandardScaler()), (svm, SVC(kernelrbf, C1.0, gammascale, random_state42)), ]) pipe.fit(X_train, y_train) print(SVM baseline acc:, pipe.score(X_test, y_test))Pipeline 在這里有兩個(gè)作用。第一把預(yù)處理和模型綁定成一個(gè)整體fit 時(shí)只學(xué)習(xí)訓(xùn)練集的均值方差predict 時(shí)自動(dòng)對測試集做同樣的 transform從結(jié)構(gòu)上杜絕數(shù)據(jù)泄漏第二和 GridSearchCV 配合時(shí)參數(shù)網(wǎng)格可以直接寫成 pipe.get_params() 的形式預(yù)處理參數(shù)和模型參數(shù)可以同時(shí)搜索代碼只需要維護(hù)一張參數(shù)表。gammascale 是 sklearn 對 RBF 核的默認(rèn)啟發(fā)式值會(huì)按特征數(shù)量自動(dòng)調(diào)整作業(yè)階段幾乎不需要手動(dòng)指定C1.0 是正則強(qiáng)度的起點(diǎn)后續(xù)網(wǎng)格搜索一般從 0.1、1、10 這幾個(gè)量級里選。注意這里接的是前面分類題的變量如果重新打開腳本單獨(dú)運(yùn)行必須先把數(shù)據(jù)加載和劃分的代碼也保留在同一文件里。baseline 跑通之后第一個(gè)該做的改進(jìn)實(shí)驗(yàn)不是換模型而是把特征標(biāo)準(zhǔn)化加上再看一遍效果。很多同學(xué)直接跳到網(wǎng)格搜索卻不清楚標(biāo)準(zhǔn)化對 SVM、邏輯回歸這類基于距離的模型影響有多大。標(biāo)準(zhǔn)化的對比實(shí)驗(yàn)只需要三行代碼卻能在報(bào)告里貢獻(xiàn)一條“預(yù)處理對精度的影響”曲線這是一道送分題不做非??上?。下面的第 3 章會(huì)講如何把這份能跑的代碼升級成一份能提交、能復(fù)現(xiàn)、能答辯的工程化代碼。3. 把代碼寫到“可復(fù)現(xiàn)”訓(xùn)練腳本、隨機(jī)種子與實(shí)驗(yàn)記錄代碼部分的高分標(biāo)準(zhǔn)不是“能跑”而是“別人能跑出和你一樣的結(jié)果”。一份可復(fù)現(xiàn)的作業(yè)代碼在提交時(shí)應(yīng)該滿足三件事執(zhí)行入口明確、隨機(jī)性可控、實(shí)驗(yàn)結(jié)果落盤。做到這三點(diǎn)答辯時(shí)老師按 README 跑一遍能復(fù)現(xiàn)你的數(shù)字項(xiàng)目就已經(jīng)進(jìn)入“工程合格”的評分檔做不到算法再花哨也容易被當(dāng)成黑匣子處理。下面按這三個(gè)目標(biāo)分別給最小實(shí)現(xiàn)。3.1 訓(xùn)練腳本的最小結(jié)構(gòu)argparse config 日志最常見的翻車現(xiàn)場是老師拿到你的 .py雙擊運(yùn)行ModuleNotFoundError 或路徑報(bào)錯(cuò)。這不是算法問題是入口和配置寫得不夠嚴(yán)格。我給自己定的紀(jì)律是任何項(xiàng)目保留一個(gè) train.py 作為唯一入口所有可調(diào)參數(shù)從命令行或配置文件注入不在代碼里寫死文件夾路徑。這樣不管是自己復(fù)盤還是老師復(fù)跑一行命令就能重現(xiàn)實(shí)驗(yàn)。下面這個(gè)骨架雖然短但結(jié)構(gòu)是完整的import argparse import time def parse_args(): parser argparse.ArgumentParser(descriptionML homework experiment) parser.add_argument(--data, defaultdata/digits.csv, helpdataset path) parser.add_argument(--model, defaultrf, choices[rf, svm, xgb]) parser.add_argument(--seed, typeint, default42) parser.add_argument(--out, defaultresults/, helpoutput dir) return parser.parse_args() def main(): args parse_args() t0 time.time() # 你的訓(xùn)練邏輯寫在這里不要散落在全局變量里 print(f[INFO] model{args.model}, seed{args.seed}, cost{time.time()-t0:.2f}s) if __name__ __main__: main()這套結(jié)構(gòu)的核心是 argparse。它把數(shù)據(jù)路徑、模型名、隨機(jī)種子全部變成運(yùn)行時(shí)參數(shù)這意味著你可以在命令行里做這樣的事同一份數(shù)據(jù)換一個(gè) --seed 跑三遍把三組數(shù)字都記在報(bào)告里證明結(jié)果不是一次性運(yùn)氣。--out 參數(shù)指定結(jié)果目錄實(shí)驗(yàn)日志和 CSV 都往這個(gè)目錄寫避免每次運(yùn)行覆蓋上次記錄。我的習(xí)慣是把每次實(shí)驗(yàn)用的命令行原樣保存在 results 下的 run_cmd.txt 里答辯被問起就能直接調(diào)出來看不需要翻聊天記錄。參數(shù)維護(hù)上少量參數(shù)用 argparse 夠用參數(shù)超過十個(gè)時(shí)換成 yaml 文件管理方向是一樣的參數(shù)不散落在代碼里。3.2 隨機(jī)種子和劃分順序讓三次運(yùn)行能跑出同一個(gè)數(shù)機(jī)器學(xué)習(xí)實(shí)驗(yàn)天然帶隨機(jī)性數(shù)據(jù)劃分的隨機(jī)、模型初始化的隨機(jī)、SGD 的采樣順序隨機(jī)。如果不固定這些隨機(jī)源同一個(gè)腳本跑兩次得到兩個(gè)精度報(bào)告里的任何數(shù)字都缺乏說服力。相反固定種子之后跑三次結(jié)果幾乎一致報(bào)告寫“準(zhǔn)確率 97.1%”就變成了一個(gè)可驗(yàn)證的聲明。固定種子相當(dāng)于給實(shí)驗(yàn)買后悔藥以后發(fā)現(xiàn)報(bào)告里某個(gè)數(shù)字可疑還能用同一條命令重新跑一遍來核實(shí)。種子問題的坑在于它不是全局設(shè)置一次就完事numpy、random、torch 各有各的隨機(jī)源漏掉其中一個(gè)在簡單模型上可能看不出來換到神經(jīng)網(wǎng)絡(luò)就明顯。import random import numpy as np def set_seed(seed: int 42): random.seed(seed) np.random.seed(seed) try: import torch torch.manual_seed(seed) torch.cuda.manual_seed_all(seed) except ImportError: pass # 沒裝 torch 時(shí)不影響其他任務(wù)邏輯說明set_seed 統(tǒng)一設(shè)置三個(gè)隨機(jī)庫的種子并把 torch 相關(guān)的 CPU、GPU 隨機(jī)源也固定避免數(shù)據(jù)加載和網(wǎng)絡(luò)初始化在不同機(jī)器上產(chǎn)生偏差。參數(shù)說明seed 取值在作業(yè)里用 42 就夠真正做研究時(shí)才需要跑多組種子取均值你在報(bào)告里只需注明種子值和設(shè)置函數(shù)的調(diào)用位置。PyTorch 的 DataLoader 還有一個(gè)細(xì)節(jié)shuffleTrue 時(shí)如果不給它顯式傳入 generator它內(nèi)部仍會(huì)使用全局隨機(jī)源光調(diào)用 set_seed 不一定夠最穩(wěn)妥的寫法是給 DataLoader 傳一個(gè)固定的 torch.Generator。另外set_seed 要放在任何隨機(jī)操作之前調(diào)用最好在 import 數(shù)據(jù)之前就調(diào)而不是在模型初始化前才調(diào)。提示固定隨機(jī)種子后如果兩次運(yùn)行結(jié)果仍有明顯差異先檢查數(shù)據(jù)讀取順序是否穩(wěn)定再檢查是否有并行操作引入了額外隨機(jī)性。dict 的遍歷順序在部分自定義代碼里也可能影響實(shí)驗(yàn)結(jié)果。3.3 訓(xùn)練過程落盤把指標(biāo)存成 CSV 而不是 print每個(gè) epoch 的 loss、準(zhǔn)確率、F1 只 print 到控制臺等于沒記錄關(guān)掉窗口就再也找不回來了。正確做法是把訓(xùn)練歷史逐行寫進(jìn) CSV再做可視化。CSV 的好處是既可以用 pandas 讀也可以直接在 Excel 里打開還能作為報(bào)告的附錄數(shù)據(jù)。我常用的記錄方式是這樣的import pandas as pd history [] # 每次 epoch 或每次實(shí)驗(yàn)追加一條 for epoch in range(10): # 這里的 train_loss 和 val_acc 要從真實(shí)訓(xùn)練循環(huán)里算出來 train_loss 0.35 - 0.02 * epoch val_acc 0.70 0.03 * epoch history.append({epoch: epoch, train_loss: train_loss, val_acc: val_acc}) df pd.DataFrame(history) df.to_csv(results/rf_seed42.csv, indexFalse)實(shí)際訓(xùn)練時(shí)train_loss 和 val_acc 要在訓(xùn)練循環(huán)里從 dataloader 或驗(yàn)證集計(jì)算這段代碼只是把記錄邏輯獨(dú)立出來。關(guān)鍵點(diǎn)是“記錄”這一步不能省。有了 CSV 之后報(bào)告里的訓(xùn)練曲線就不要用截圖了直接從這個(gè)文件畫圖表區(qū)間一致、數(shù)據(jù)真實(shí)。epoch 次數(shù)在表格數(shù)據(jù)集上建議取 20 到 50圖像任務(wù) 50 到 100超過這個(gè)范圍收益很小結(jié)果文件名建議帶模型名和種子如 rf_seed42.csv避免多組實(shí)驗(yàn)互相覆蓋。如果答辯時(shí)老師要求現(xiàn)場重跑你只需要讓他看這個(gè) CSV 文件的修改時(shí)間證明這是這臺機(jī)器上剛生成的而不是從別處找來的。4. 實(shí)驗(yàn)報(bào)告按評分點(diǎn)組織摘要、數(shù)據(jù)、方法、結(jié)果一個(gè)都不能少實(shí)驗(yàn)報(bào)告本質(zhì)上是給評審的一份證明文件證明你讀懂了數(shù)據(jù)證明你的方法有依據(jù)證明你的結(jié)果是真實(shí)實(shí)驗(yàn)出來的。評審看一份大作業(yè)報(bào)告的時(shí)間通常只有幾分鐘動(dòng)作不外乎三個(gè)先讀摘要再翻圖表最后查參數(shù)表。所以報(bào)告的結(jié)構(gòu)應(yīng)該按這三個(gè)動(dòng)作設(shè)計(jì)而不是按你寫代碼的順序。下面按六個(gè)段落展開每段都有明確的交付目標(biāo)。4.1 問題定義與數(shù)據(jù)理解寫清“為什么選這個(gè)題”摘要控制在 150 字以內(nèi)寫清三件事就夠了用了什么數(shù)據(jù)、做了什么任務(wù)、最好結(jié)果是多少。比如“基于銀行營銷電話數(shù)據(jù)集構(gòu)建客戶定期存款認(rèn)購預(yù)測模型通過邏輯回歸、隨機(jī)森林與 XGBoost 的對比實(shí)驗(yàn)最優(yōu)模型在測試集上 F1 達(dá)到 91.2%”。如果你用的算法比較多摘要里只提最有說服力的一個(gè)其余讓實(shí)驗(yàn)部分去說明。具體數(shù)字換成你自己實(shí)驗(yàn)跑出來的即可格式照抄。數(shù)據(jù)理解段要回答四個(gè)問題數(shù)據(jù)從哪來、字段含義是什么、樣本量有多少、類別是否平衡。這四件事用一段文字加一個(gè)字段表就能講完不需要長篇大論。字段表要像論文里的 Table 那樣寫字段名、類型、缺失率、處理方式占四列。數(shù)據(jù)處理那一節(jié)被很多同學(xué)跳過但“機(jī)器學(xué)習(xí)中的數(shù)據(jù)處理是什么”這個(gè)問題的答案恰好就是報(bào)告里最容易拿分的一段。標(biāo)準(zhǔn)化、缺失值填充、類別編碼、離群點(diǎn)處理每一行處理都要寫“為什么這么做”。比如“age 字段存在 5 個(gè) 999 的異常值視為缺失并填充中位數(shù)”這個(gè)粒度就夠了。不要把所有處理混成一句“對數(shù)據(jù)進(jìn)行了標(biāo)準(zhǔn)化”那等于沒說。表格示例如下字段類型缺失率處理方式age數(shù)值0%標(biāo)準(zhǔn)化job類別2.1%眾數(shù)填充y二分類0%無需處理4.2 方法描述與參數(shù)表把“調(diào)了什么”寫成人話方法段最常見的錯(cuò)誤是大段貼代碼。代碼對評審沒有信息量他要看的是一張“方法參數(shù)”對照表。模型名加關(guān)鍵參數(shù)、訓(xùn)練時(shí)間、測試指標(biāo)四列一表基本覆蓋所有疑問。寫參數(shù)時(shí)要避免兩種極端一個(gè)參數(shù)不寫或者把所有參數(shù)全部抄一遍。只寫那些會(huì)影響結(jié)果的參數(shù)比如 SVM 寫核函數(shù)、C、gamma隨機(jī)森林寫 n_estimators、max_depth神經(jīng)網(wǎng)絡(luò)寫學(xué)習(xí)率、batch size、epoch。表格里加一列訓(xùn)練時(shí)間能反映你對計(jì)算代價(jià)的考慮這在模型對比時(shí)尤其重要。模型的選型理由也要寫一句不是從網(wǎng)上抄的定義而是基于數(shù)據(jù)特性的一句話。比如“數(shù)據(jù)維度較高且可能線性不可分因此使用 RBF 核 SVM”“特征間可能存在交互隨機(jī)森林對這種結(jié)構(gòu)更魯棒”。這句話不需要非常嚴(yán)謹(jǐn)被追問時(shí)有你自己的思考就行。方法段末尾要交代評價(jià)指標(biāo)和劃分方式比如“采用 8:2 分層劃分以準(zhǔn)確率和加權(quán) F1 作為評價(jià)指標(biāo)”。劃分方式?jīng)Q定結(jié)果能否橫向比較不寫清楚的話后面所有數(shù)字都懸空。參數(shù)表的參考樣式模型關(guān)鍵參數(shù)訓(xùn)練時(shí)間測試準(zhǔn)確率邏輯回歸C1.00.2s92.3%SVM-RBFC10, gamma0.011.8s96.5%隨機(jī)森林n_estimators200, max_depth103.2s97.1%4.3 結(jié)果對比與結(jié)論差 0.5% 也要解釋原因結(jié)果段用一張總表開頭列出每個(gè)模型在測試集上的指標(biāo)隨后用一張訓(xùn)練曲線圖說明收斂情況??偙淼母袷街苯記Q定評審耐心模型名、準(zhǔn)確率、F1、訓(xùn)練時(shí)間四列足夠。這里有個(gè)小原則所有結(jié)果必須是同一次劃分、同一個(gè)測試集上跑出來的不能模型 A 用在 8:2 劃分、模型 B 用在交叉驗(yàn)證上兩種結(jié)果放進(jìn)同一張表是不可比的。如果用了交叉驗(yàn)證就在表里寫 mean±std例如 96.8%±0.4%這比單一數(shù)字有力得多。結(jié)論段不要說“模型表現(xiàn)良好”要解釋“為什么這個(gè)模型最適合這個(gè)數(shù)據(jù)”。哪怕是“SVM 在這個(gè) 64 維特征空間里找到的分隔面比隨機(jī)森林更干凈”這種不完全嚴(yán)謹(jǐn)?shù)脑捯舱故玖朔治瞿芰?。如果兩個(gè)模型精度只差 0.5%更需要解釋是隨機(jī)波動(dòng)還是確實(shí)提升了你可以寫“兩者差異小于交叉驗(yàn)證的標(biāo)準(zhǔn)差因此認(rèn)為性能相當(dāng)”這句話既誠實(shí)又能防止被追問。報(bào)告最后還可以加一小段“不足與改進(jìn)”寫“數(shù)據(jù)量較小導(dǎo)致深度模型優(yōu)勢不明顯后續(xù)可以收集更多數(shù)據(jù)微調(diào)預(yù)訓(xùn)練模型”這比硬吹自己的模型好很多。5. 大作業(yè)避坑指南五個(gè)讓分?jǐn)?shù)腰斬的典型問題5.1 數(shù)據(jù)泄漏訓(xùn)練集里混進(jìn)了測試集現(xiàn)象訓(xùn)練準(zhǔn)確率正常但測試集分?jǐn)?shù)高得離譜比如 99.8%或者老師重跑時(shí)你的分?jǐn)?shù)完全對不上。原因數(shù)據(jù)劃分之前就做了標(biāo)準(zhǔn)化或缺失值填充讓測試集的信息提前進(jìn)入了訓(xùn)練過程。比如對整個(gè) X 調(diào)用 fit_transform再從結(jié)果里切分訓(xùn)練測試集這屬于教科書級泄漏。解決把預(yù)處理放進(jìn) Pipeline或者嚴(yán)格按“先劃分再對訓(xùn)練集 fit_transform、對測試集只 transform”的順序?qū)憽W圆榉椒ㄊ侨乃阉?fit(X_all) 和 fit_transform(X_all)出現(xiàn)基本就是泄漏。5.2 報(bào)告貼了代碼但沒貼結(jié)果現(xiàn)象實(shí)驗(yàn)報(bào)告一半篇幅是代碼翻到最后一頁沒有評估表、沒有曲線、沒有日志輸出。原因把“代碼能跑”當(dāng)成“實(shí)驗(yàn)完成”結(jié)果只存在于控制臺窗口關(guān)了就沒了。解決訓(xùn)練腳本必須寫 CSV報(bào)告里引用 results 目錄下的實(shí)際文件。答辯時(shí)被問“你這個(gè)準(zhǔn)確率哪來的”你的回答應(yīng)該是“rf_seed42.csv 里的第五行測試集 10 折平均”而不是“好像之前跑出來過”。5.3 畫圖不標(biāo)軸、不標(biāo)單位現(xiàn)象圖上只有兩條彩色折線沒有橫軸名、沒有縱軸名、沒有圖例標(biāo)題叫“Figure 1”。原因matplotlib 的默認(rèn)風(fēng)格太樸素而大家普遍覺得“能顯示就行”。解決統(tǒng)一畫圖模板每個(gè)圖至少包含 title、xlabel、ylabel、legend需要對比時(shí)再加 grid保存 dpi 不低于 150。寫一個(gè) plot_results(file) 工具函數(shù)所有實(shí)驗(yàn)共用它風(fēng)格一致省去逐個(gè)調(diào)圖的時(shí)間。圖里曲線描述也要寫清楚比如“實(shí)線是訓(xùn)練損失虛線是驗(yàn)證損失”不要只丟一張圖。5.4 超參數(shù)全靠猜現(xiàn)象SVM 參數(shù)寫成 C100、gamma0.001被問為什么選這個(gè)時(shí)回答“試出來的”。原因沒有系統(tǒng)搜索試了兩三組就挑了訓(xùn)練集分?jǐn)?shù)最高的后面報(bào)告也無法解釋。解決用 GridSearchCV 跑一個(gè)小范圍網(wǎng)格比如 C 取 0.1/1/10gamma 取 0.01/0.1/125 組組合在小數(shù)據(jù)集上幾秒跑完。把網(wǎng)格搜索結(jié)果放進(jìn)報(bào)告至少包含“最優(yōu)參數(shù)”和“搜索范圍”兩行這比“試出來的”可信太多。搜索范圍不要太大作業(yè)不是競賽你能解釋清楚為什么搜這幾組比搜幾百組更有價(jià)值。5.5 全篇只有一個(gè)模型、一組默認(rèn)參數(shù)現(xiàn)象報(bào)告三千字實(shí)驗(yàn)部分只有“隨機(jī)森林默認(rèn)參數(shù)準(zhǔn)確率 95.3%”沒有對比只有結(jié)論。原因時(shí)間不夠或者認(rèn)為模型越高級分越高忽略了“對比實(shí)驗(yàn)”本身就是評分點(diǎn)。解決保證至少三個(gè)模型參與對比其中一個(gè)是樸素 baseline。邏輯回歸、SVM、隨機(jī)森林是整個(gè)機(jī)器學(xué)習(xí)課程里最常涉及的三個(gè)算法覆蓋三種不同的建模思路報(bào)告結(jié)構(gòu)天然成立。有余力再補(bǔ)一個(gè)網(wǎng)格搜索后的最優(yōu)模型對比表和討論就完整了。6. 比分再往上提一檔交叉驗(yàn)證與消融實(shí)驗(yàn)的寫法6.1 用 K-Fold 替代單次劃分單次 train_test_split 在作業(yè)里夠用但有個(gè)明顯隱患這次劃分恰好容易或恰好難你的結(jié)論就被偶然綁架。課程項(xiàng)目里我一般用 5 折分層交叉驗(yàn)證替代輸出 mean±std報(bào)告的結(jié)論立刻從“某個(gè)劃分下的表現(xiàn)”變成“模型在這份數(shù)據(jù)上的穩(wěn)定表現(xiàn)”。實(shí)現(xiàn)只要幾行from sklearn.model_selection import StratifiedKFold, cross_val_score cv StratifiedKFold(n_splits5, shuffleTrue, random_state42) scores cross_val_score(rf, X, y, cvcv, scoringaccuracy) print(facc: {scores.mean():.4f} ± {scores.std():.4f})StratifiedKFold 在分類問題里保證每一折的類別比例和全量數(shù)據(jù)一致不會(huì)出現(xiàn)某一折恰好缺一類的極端情況shuffleTrue 配合 random_state 讓折的劃分可復(fù)現(xiàn)。scores.mean 和 scores.std 對應(yīng)報(bào)告表里的“96.8%±0.4%”如果兩組模型的均值差小于標(biāo)準(zhǔn)差結(jié)論就寫“性能相當(dāng)”不要硬說某個(gè)模型更強(qiáng)?;貧w題上把 StratifiedKFold 換成 KFold 即可邏輯完全一樣。6.2 消融實(shí)驗(yàn)讓報(bào)告的每個(gè)設(shè)計(jì)都有存在理由比交叉驗(yàn)證更能拉高印象分的是消融實(shí)驗(yàn)。做法很簡單每次從你的方案里去掉一部分看指標(biāo)掉多少。比如隨機(jī)森林方案里有標(biāo)準(zhǔn)化和特征篩選兩步就分別做“去掉標(biāo)準(zhǔn)化”和“去掉特征篩選”兩個(gè)變體。結(jié)果用一張三行表呈現(xiàn)設(shè)置準(zhǔn)確率/F1變化完整方案97.1%—去掉標(biāo)準(zhǔn)化95.8%-1.3%去掉特征篩選96.4%-0.7%哪個(gè)部分去掉后指標(biāo)掉得最多哪個(gè)就是你的主要貢獻(xiàn)點(diǎn)。這張表放在結(jié)論前面比任何文字都說明問題。我當(dāng)年交大作業(yè)時(shí)模型本身只比 baseline 高了兩個(gè)點(diǎn)但消融表證明這兩個(gè)點(diǎn)來自特征篩選而不是來自運(yùn)氣最后拿到的分?jǐn)?shù)比同組那些“模型更復(fù)雜”的同學(xué)都高。這個(gè)習(xí)慣我一直保留到現(xiàn)在每次做完實(shí)驗(yàn)先問一句“哪個(gè)模塊真的有用”希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取