一等獎(jiǎng)到國賽線0.003之差:數(shù)據(jù)競賽完整復(fù)盤與避坑指南)
引言那場比賽結(jié)束后榜單上賽區(qū)一等獎(jiǎng)的綠色標(biāo)記還掛在隊(duì)伍名下可國賽入圍線卻停在差 0.003 的位置像一層透明的玻璃看得見對面指尖卻怎么也按不過去。賽后復(fù)盤了整整三天從數(shù)據(jù)清洗、特征工程到模型調(diào)參、融合策略把每一份日志翻了個(gè)底朝天。最后發(fā)現(xiàn)問題并不是出在某個(gè)“靈光一現(xiàn)”的騷操作上而是一連串看起來不起眼的小細(xì)節(jié)疊加起來把最后那一段分?jǐn)?shù)悄悄吃掉了。這篇文章不是來訴苦的而是把整個(gè)競賽項(xiàng)目的技術(shù)實(shí)現(xiàn)、踩坑過程、評分波動(dòng)原因和復(fù)盤結(jié)論完整拆出來。如果你也在準(zhǔn)備數(shù)據(jù)挖掘或機(jī)器學(xué)習(xí)類競賽或者正在做類似的任務(wù)型建模項(xiàng)目這篇復(fù)盤應(yīng)該能幫你避開不少彎路。我們會按照“背景說明 → 環(huán)境準(zhǔn)備 → 基線建模 → 調(diào)優(yōu)過程 → 翻車復(fù)盤 → 排錯(cuò)思路 → 工程建議”的順序展開代碼盡量完整方便直接復(fù)現(xiàn)。1. 背景與核心概念1.1 這是一場什么類型的競賽這類比賽通常不會直接給你一份干干凈凈的數(shù)據(jù)而是提供一個(gè)經(jīng)過脫敏或匿名化處理的表格型數(shù)據(jù)集。訓(xùn)練集包含若干特征列和一個(gè)目標(biāo)標(biāo)簽列測試集只給特征參賽者需要訓(xùn)練出模型去預(yù)測測試集中的目標(biāo)值主辦方再用預(yù)測結(jié)果和真實(shí)標(biāo)簽對比得到線上評分。這種任務(wù)看起來簡單實(shí)際做起來卻非常折磨人。原因有兩個(gè)特征列被匿名化成f_1、f_2這樣的編號無法從業(yè)務(wù)含義出發(fā)做針對性的特征篩選。評價(jià)指標(biāo)不同策略完全不同。有的比賽看重 AUC有的看重 F1有的則直接使用業(yè)務(wù)自定義的加權(quán)指標(biāo)。本文討論的場景是二分類任務(wù)評估指標(biāo)采用 AUC 和 F1 綜合判斷這和數(shù)據(jù)競賽里最常見的設(shè)定基本一致。1.2 為什么賽區(qū)一等獎(jiǎng)并不等于進(jìn)國賽很多第一次參賽的選手會誤以為“拿了一等獎(jiǎng)就一定晉級”。實(shí)際上不少賽事是分賽區(qū)評獎(jiǎng)同時(shí)在全國范圍內(nèi)劃定統(tǒng)一的晉級分?jǐn)?shù)線。賽區(qū)一等獎(jiǎng)只能說明你在本賽區(qū)相對排名靠前但國賽晉級看的是全國排名或者絕對分?jǐn)?shù)。這就是“賽區(qū)一等獎(jiǎng)國賽門檻卻在指尖擦過”的根本原因相對名次好看絕對分?jǐn)?shù)不夠。從技術(shù)層面來說這種情況往往意味著模型泛化能力沒有想象中強(qiáng)本地交叉驗(yàn)證分?jǐn)?shù)虛高。特征工程后勁不足測試集上的表現(xiàn)受分布變化影響大。模型融合帶來的提升沒有覆蓋掉單模型的不穩(wěn)定性。理解這一點(diǎn)很重要因?yàn)楹罄m(xù)所有的優(yōu)化都應(yīng)該圍繞“絕對分?jǐn)?shù)提升”和“泛化穩(wěn)定性”去做而不是只看本地分?jǐn)?shù)。1.3 這篇文章你能學(xué)到什么一份完整的表格型二分類競賽建模流程。特征工程里容易忽略卻影響很大的坑。本地交叉驗(yàn)證分?jǐn)?shù)與線上分?jǐn)?shù)不一致的常見原因。一份可以直接套用的 LightGBM 訓(xùn)練模板。最后的工程復(fù)盤清單能幫你少踩 80% 的重復(fù)坑。2. 環(huán)境準(zhǔn)備與版本說明2.1 基礎(chǔ)環(huán)境本文示例代碼使用 Python 編寫建議使用 Python 3.8 及以上版本。依賴庫建議如下庫名用途說明pandas數(shù)據(jù)讀取、處理版本 1.x / 2.x 均可numpy數(shù)值計(jì)算配合 pandas 使用scikit-learn交叉驗(yàn)證、評估指標(biāo)版本 1.0lightgbm核心模型3.3.x 及以上版本均可xgboost輔助模型如需做模型融合時(shí)使用matplotlib / seaborn可視化特征分析和結(jié)果展示安裝命令pip install pandas numpy scikit-learn lightgbm xgboost matplotlib seaborn需要說明的是不同版本的 LightGBM 在參數(shù)細(xì)節(jié)和默認(rèn)行為上會有差異比如early_stopping的寫法在新舊版本中就有變化。本文代碼以常見穩(wěn)定版本為準(zhǔn)如果你使用的版本更新需要按官方文檔微調(diào)參數(shù)。2.2 數(shù)據(jù)格式說明競賽提供的數(shù)據(jù)通常長這樣train.csv test.csv sample_submission.csv核心字段約定字段含義id樣本唯一標(biāo)識f_1 ~ f_n匿名特征列l(wèi)abel訓(xùn)練集目標(biāo)列取值為 0 或 1這是非常經(jīng)典的表格型競賽數(shù)據(jù)格式很多實(shí)戰(zhàn)項(xiàng)目里也能遇到類似結(jié)構(gòu)。2.3 評估方式二分類任務(wù)常見評估指標(biāo)包括準(zhǔn)確率Accuracy整體預(yù)測正確的比例適合正負(fù)樣本均衡的情況。AUCArea Under Curve衡量模型把正樣本排在前面的能力對類別不平衡不敏感。F1-Score精確率和召回率的調(diào)和平均對少數(shù)類更敏感。LogLoss衡量預(yù)測概率和真實(shí)標(biāo)簽之間的交叉熵?fù)p失。對于數(shù)據(jù)挖掘類競賽AUC 是最常見的指標(biāo)之一。因?yàn)樾庞每L(fēng)控、用戶流失預(yù)測、廣告點(diǎn)擊率預(yù)測這類場景關(guān)注的重點(diǎn)不是“預(yù)測是否準(zhǔn)確”而是“高風(fēng)險(xiǎn)樣本是否被排在前面”。3. 基線建模從零到第一個(gè)可提交結(jié)果3.1 數(shù)據(jù)加載與基礎(chǔ)檢查先加載數(shù)據(jù)觀察數(shù)據(jù)規(guī)模和缺失情況這是建模的第一步。import pandas as pd import numpy as np train pd.read_csv(train.csv) test pd.read_csv(test.csv) print(train shape:, train.shape) print(test shape:, test.shape) print(train columns:, train.columns.tolist()) print(label distribution:) print(train[label].value_counts()) # 缺失值檢查 missing_train train.isnull().sum() missing_train missing_train[missing_train 0].sort_values(ascendingFalse) print(columns with missing values in train:) print(missing_train)這段代碼做的事情很簡單卻非常重要。訓(xùn)練集和測試集的形狀可以讓我們判斷特征是否對齊標(biāo)簽分布能幫助我們判斷是否面臨類別不平衡問題缺失值統(tǒng)計(jì)結(jié)果則直接決定后續(xù)特征工程需要采用哪種填充策略。3.2 劃分驗(yàn)證集很多新手會直接拿全部訓(xùn)練數(shù)據(jù)訓(xùn)練模型然后在測試集上預(yù)測提交。這是非常危險(xiǎn)的因?yàn)槟銦o法評估模型真正的好壞也無法判斷是否過擬合。正確做法是先劃分出一部分訓(xùn)練數(shù)據(jù)作為本地驗(yàn)證集模擬線上評測。from sklearn.model_selection import train_test_split features [c for c in train.columns if c not in [id, label]] X train[features] y train[label] X_train, X_valid, y_train, y_valid train_test_split( X, y, test_size0.2, stratifyy, random_state42 ) print(X_train shape:, X_train.shape) print(X_valid shape:, X_valid.shape)這里使用stratifyy做分層抽樣保證訓(xùn)練集和驗(yàn)證集中正負(fù)樣本的比例和原始數(shù)據(jù)一致。如果不做分層處理在標(biāo)簽不平衡的數(shù)據(jù)集上驗(yàn)證集可能恰好缺少數(shù)類樣本導(dǎo)致評估結(jié)果失真。3.3 第一版 LightGBM 模型LightGBM 是表格型數(shù)據(jù)建模中最常用的模型之一訓(xùn)練速度快效果穩(wěn)定對缺失值和異常值有一定容忍度。這里先給一版最簡單的訓(xùn)練代碼不做過多的特征工程目的是快速跑通流程拿到一個(gè)可用分?jǐn)?shù)。import lightgbm as lgb from sklearn.metrics import roc_auc_score params { objective: binary, metric: auc, learning_rate: 0.05, num_leaves: 31, max_depth: -1, min_child_samples: 20, feature_fraction: 0.8, bagging_fraction: 0.8, bagging_freq: 1, lambda_l1: 0.1, lambda_l2: 0.1, random_state: 42, verbosity: -1, } d_train lgb.Dataset(X_train, labely_train) d_valid lgb.Dataset(X_valid, labely_valid) model lgb.train( params, d_train, num_boost_round10000, valid_sets[d_valid], callbacks[ lgb.early_stopping(100), lgb.log_evaluation(200) ] ) valid_pred model.predict(X_valid, num_iterationmodel.best_iteration) auc roc_auc_score(y_valid, valid_pred) print(Validation AUC {:.6f}.format(auc))跑完之后用同樣的邏輯預(yù)測測試集把結(jié)果保存成提交格式。test_pred model.predict(test[features], num_iterationmodel.best_iteration) submission pd.DataFrame({ id: test[id], label: test_pred }) submission.to_csv(submission_v1.csv, indexFalse) print(submission.head())第一版模型可能已經(jīng)能拿到一個(gè)不錯(cuò)的分?jǐn)?shù)也就是進(jìn)入賽區(qū)一等獎(jiǎng)門檻的分?jǐn)?shù)。但距離國賽線往往還差一口氣。3.4 基線結(jié)果說明基線版本的作用不是炫技而是建立一個(gè)可參照的起點(diǎn)。之后的任何優(yōu)化都需要和這個(gè)基線做對比否則很難判斷某個(gè)操作到底是提升還是降低。從實(shí)際比賽經(jīng)驗(yàn)來看一份簡單的 LightGBM 基線通常能排進(jìn)中上游位置。真正拉開差距的是后續(xù)的特征工程、交叉驗(yàn)證策略、調(diào)參與融合。4. 特征工程的幾個(gè)關(guān)鍵方向4.1 缺失值統(tǒng)計(jì)特征在匿名特征的數(shù)據(jù)集中缺失值本身往往就是信息。某個(gè)樣本缺失的特征特別多可能表示這個(gè)樣本本身質(zhì)量不高或者它的數(shù)據(jù)來源和完整樣本不同。def add_missing_features(df): df df.copy() df[null_count] df.isnull().sum(axis1) df[null_ratio] df[null_count] / df.shape[1] return df train add_missing_features(train) test add_missing_features(test)4.2 數(shù)值分布聚合特征如果特征列全部是數(shù)值型可以把每一行當(dāng)作一個(gè)向量計(jì)算它的統(tǒng)計(jì)量。這樣做的依據(jù)是在某些數(shù)據(jù)生成場景下同一類樣本的特征分布在均值、方差等統(tǒng)計(jì)量上會呈現(xiàn)出相似的模式。def add_stats_features(df): df df.copy() num_cols [c for c in df.columns if c.startswith(f_)] df[row_mean] df[num_cols].mean(axis1) df[row_std] df[num_cols].std(axis1) df[row_min] df[num_cols].min(axis1) df[row_max] df[num_cols].max(axis1) df[row_range] df[row_max] - df[row_min] df[row_skew] df[num_cols].skew(axis1) return df train add_stats_features(train) test add_stats_features(test)這種行級統(tǒng)計(jì)特征在一些匿名特征競賽里非常有效但要注意不要過度使用否則容易把噪聲也學(xué)進(jìn)去。4.3 特征交互簡單的特征之間的加減乘除組合有時(shí)可以捕捉到單個(gè)特征無法表達(dá)的關(guān)系。def add_interaction_features(df): df df.copy() df[inter_1] df[f_1] * df[f_2] df[inter_2] df[f_3] df[f_4] df[inter_3] df[f_5] / (df[f_6] 1e-6) return df注意交互特征不是越多越好。每一輪新增特征之后都要用交叉驗(yàn)證重新評估。如果分?jǐn)?shù)沒有提升甚至下降了應(yīng)該果斷刪除這部分特征。4.4 特征篩選特征篩選的核心思路是保留對模型預(yù)測有幫助的特征刪除冗余或無用的特征。推薦使用 LightGBM 的特征重要性做初步排序篩選出重要性為 0 的特征然后結(jié)合驗(yàn)證分?jǐn)?shù)去驗(yàn)證刪除這些特征后的效果。importance pd.DataFrame({ feature: model.feature_name(), importance: model.feature_importance(gain) }).sort_values(importance, ascendingFalse) zero_importance importance[importance[importance] 0][feature].tolist() print(zero importance features count:, len(zero_importance)) print(zero_importance[:20])5. 交叉驗(yàn)證策略為什么你的分?jǐn)?shù)會虛高5.1 單次劃分的問題前面我們使用train_test_split劃分了一次訓(xùn)練集和驗(yàn)證集。這種方法速度快適合快速迭代但存在明顯的問題驗(yàn)證結(jié)果對劃分方式敏感。同一個(gè)模型換一個(gè)隨機(jī)種子驗(yàn)證分?jǐn)?shù)可能波動(dòng)很大。沒有充分利用數(shù)據(jù)。訓(xùn)練集只用了 80% 的數(shù)據(jù)信息有浪費(fèi)。5.2 K 折交叉驗(yàn)證K 折交叉驗(yàn)證的思路是把訓(xùn)練數(shù)據(jù)分成 K 份每次用 K-1 份訓(xùn)練1 份驗(yàn)證循環(huán) K 次最終得到 K 組驗(yàn)證分?jǐn)?shù)并取平均。from sklearn.model_selection import StratifiedKFold def train_kfold(X, y, params, n_splits5, seed42): skf StratifiedKFold(n_splitsn_splits, shuffleTrue, random_stateseed) oof np.zeros(len(X)) models [] scores [] for fold, (tr_idx, va_idx) in enumerate(skf.split(X, y)): X_tr, X_va X.iloc[tr_idx], X.iloc[va_idx] y_tr, y_va y.iloc[tr_idx], y.iloc[va_idx] d_train lgb.Dataset(X_tr, labely_tr) d_valid lgb.Dataset(X_va, labely_va) model lgb.train( params, d_train, num_boost_round10000, valid_sets[d_valid], callbacks[ lgb.early_stopping(100), lgb.log_evaluation(500) ] ) fold_pred model.predict(X_va, num_iterationmodel.best_iteration) oof[va_idx] fold_pred fold_auc roc_auc_score(y_va, fold_pred) scores.append(fold_auc) models.append(model) print(ffold {fold 1} AUC {fold_auc:.6f}) print(mean AUC {:.6f} (/- {:.6f}).format(np.mean(scores), np.std(scores))) return oof, models, scores調(diào)用方式oof, models, scores train_kfold(X, y, params, n_splits5)最終oof是所有訓(xùn)練樣本的折疊外預(yù)測結(jié)果用它計(jì)算的整體 AUC 可以作為模型真實(shí)泛化能力的參考。5.3 時(shí)間序列數(shù)據(jù)的特殊處理如果數(shù)據(jù)帶有明顯的時(shí)間順序那么隨機(jī)劃分交叉驗(yàn)證是錯(cuò)誤的選擇。因?yàn)橛?xùn)練集和驗(yàn)證集之間會產(chǎn)生時(shí)間上的重疊導(dǎo)致驗(yàn)證分?jǐn)?shù)虛高。這種情況下應(yīng)該使用時(shí)序劃分訓(xùn)練集使用較早時(shí)間段的數(shù)據(jù)驗(yàn)證集使用較晚時(shí)間段的數(shù)據(jù)。train_time train.sort_values(time_col) cutoff int(len(train_time) * 0.8) train_part train_time.iloc[:cutoff] valid_part train_time.iloc[cutoff:]如果比賽沒有明確給出時(shí)間列可以通過分析特征分布隨樣本序號的變化來判斷是否存在時(shí)序性。6. 調(diào)參經(jīng)驗(yàn)真正有用的幾個(gè)方向6.1 學(xué)習(xí)率與迭代次數(shù)學(xué)習(xí)率越低模型越不容易過擬合但需要的迭代次數(shù)也越多。常見做法是先用一個(gè)較大的學(xué)習(xí)率快速確定大致的迭代范圍再降低學(xué)習(xí)率進(jìn)行細(xì)化訓(xùn)練。一個(gè)常用的技巧是使用帶衰減的learning_rate或者在訓(xùn)練中期手動(dòng)降低學(xué)習(xí)率繼續(xù)訓(xùn)練。6.2 樹模型復(fù)雜度控制如果本地驗(yàn)證分?jǐn)?shù)很高但線上分?jǐn)?shù)明顯低于預(yù)期通常是過擬合了。此時(shí)應(yīng)該增加正則化參數(shù)或者降低模型復(fù)雜度減小num_leaves增大min_child_samples增大lambda_l1和lambda_l2降低feature_fraction和bagging_fraction6.3 類別不平衡處理如果數(shù)據(jù)中正樣本占比很低比如不足 5%需要考慮以下處理方式使用is_unbalanceTrue讓 LightGBM 自動(dòng)調(diào)整樣本權(quán)重。手動(dòng)設(shè)置scale_pos_weight。在評估時(shí)重點(diǎn)關(guān)注 AUC 而不是 Accuracy。對預(yù)測概率做閾值搜索找到 F1 最優(yōu)的閾值。# 計(jì)算正負(fù)樣本比例 pos_num (y 1).sum() neg_num (y 0).sum() params[scale_pos_weight] neg_num / pos_num6.4 為什么不要在參數(shù)上花太多時(shí)間在數(shù)據(jù)挖掘競賽中參數(shù)調(diào)優(yōu)帶來的提升幅度通常有限大概在 0.001 到 0.003 的 AUC 范圍內(nèi)。而一個(gè)穩(wěn)定的交叉驗(yàn)證策略、一份高質(zhì)量的特征工程可能帶來 0.01 甚至更高的提升。因此合理的分配方式是特征工程占 50% 精力。交叉驗(yàn)證與融合策略占 30% 精力。單模型調(diào)參占 20% 精力。7. 翻車復(fù)盤國賽門檻差在哪7.1 本地分?jǐn)?shù)與線上分?jǐn)?shù)不一致這是本次比賽最核心的問題之一。復(fù)盤時(shí)發(fā)現(xiàn)本地交叉驗(yàn)證 AUC 和線上公開榜分?jǐn)?shù)之間始終存在大約 0.004 到 0.006 的差距。造成這個(gè)現(xiàn)象的原因可能有很多可能性說明驗(yàn)證方法數(shù)據(jù)分布不同訓(xùn)練集和測試集來自不同分布比較特征分布、使用對抗驗(yàn)證隨機(jī)種子不穩(wěn)定模型對隨機(jī)種子敏感換 5 個(gè)種子跑多次觀察分?jǐn)?shù)波動(dòng)特征泄漏某些特征間接包含了標(biāo)簽信息檢查特征與標(biāo)簽的異常高關(guān)聯(lián)過擬合模型記住了訓(xùn)練集噪聲增大正則化、減少迭代7.2 對抗驗(yàn)證檢測訓(xùn)練集和測試集是否存在分布偏移對抗驗(yàn)證的思路非常簡單把訓(xùn)練集和測試集分別打上標(biāo)簽 0 和 1然后訓(xùn)練一個(gè)分類器去區(qū)分它們。如果分類器很容易區(qū)分出哪個(gè)樣本來自訓(xùn)練集、哪個(gè)樣本來自測試集就說明兩個(gè)數(shù)據(jù)集存在明顯的分布差異。from sklearn.model_selection import cross_val_score train[is_test] 0 test[is_test] 1 all_data pd.concat([train, test], axis0, ignore_indexTrue) features [c for c in all_data.columns if c.startswith(f_)] X_adv all_data[features] y_adv all_data[is_test] model_adv lgb.LGBMClassifier( n_estimators100, learning_rate0.1, num_leaves31, random_state42 ) scores cross_val_score(model_adv, X_adv, y_adv, cv5, scoringroc_auc) print(adversarial validation AUC:, np.mean(scores))如果對抗驗(yàn)證的 AUC 接近 0.9 甚至更高說明訓(xùn)練集和測試集之間的差異非常大。此時(shí)即使本地分?jǐn)?shù)再高也不能保證線上分?jǐn)?shù)穩(wěn)定。7.3 特征泄漏的排查特征泄漏指的是特征中包含了未來信息或標(biāo)簽信息導(dǎo)致模型在訓(xùn)練時(shí)“偷看”了答案。匿名特征中很難直接發(fā)現(xiàn)泄漏但可以通過以下方式排查查看哪些特征與標(biāo)簽的相關(guān)性異常高。查看有多少特征在訓(xùn)練集和測試集中的分布完全一致。嘗試單獨(dú)使用某個(gè)特征訓(xùn)練模型看 AUC 是否異常高。如果發(fā)現(xiàn)某個(gè)特征單獨(dú)訓(xùn)練就能達(dá)到很高的 AUC比如超過 0.85那么大概率存在泄漏。這種特征在測試集中可能并不可靠。7.4 模型融合的利與弊模型融合通常能提升分?jǐn)?shù)但如果使用不當(dāng)也會帶來負(fù)面影響。本次復(fù)盤發(fā)現(xiàn)在單模型基礎(chǔ)上加入簡單的加權(quán)融合后本地分?jǐn)?shù)提升了 0.002但線上分?jǐn)?shù)反而沒有明顯變化甚至略有下降。原因可能是融合時(shí)使用的權(quán)重過擬合了本地驗(yàn)證集導(dǎo)致融合后的模型泛化能力不如單個(gè)最優(yōu)模型。更穩(wěn)健的做法是在多個(gè)隨機(jī)種子、多個(gè)折上評估融合效果。融合時(shí)采用簡單的平均而非復(fù)雜加權(quán)。避免融合太多相關(guān)性過高的模型。8. 常見問題與排查思路8.1 問題表格問題現(xiàn)象常見原因解決思路本地 CV 很高線上分?jǐn)?shù)低過擬合增大正則化、降低模型復(fù)雜度不同隨機(jī)種子分?jǐn)?shù)波動(dòng)大數(shù)據(jù)量不足或模型不穩(wěn)定增加交叉驗(yàn)證折數(shù)、使用 bagging特征工程加了特征反而掉分特征中帶噪聲或冗余使用特征重要性分析并篩選訓(xùn)練速度越來越慢特征數(shù)量過多或數(shù)據(jù)量增大減少特征、使用 GPU 版本預(yù)測結(jié)果全是同一類閾值選擇不當(dāng)或模型退化檢查預(yù)測分布、調(diào)整閾值LightGBM 訓(xùn)練報(bào)錯(cuò)版本差異導(dǎo)致參數(shù)不兼容檢查參數(shù)名和 API 變化8.2 排查順序建議當(dāng)模型分?jǐn)?shù)不符合預(yù)期時(shí)按以下順序排查檢查評估指標(biāo)是否用錯(cuò)。檢查數(shù)據(jù)預(yù)處理是否泄漏。查看本地交叉驗(yàn)證的穩(wěn)定性。用對抗驗(yàn)證判斷訓(xùn)練集和測試集分布差異。檢查預(yù)測概率分布是否正常。最后才考慮參數(shù)調(diào)優(yōu)和模型融合。這個(gè)順序的核心邏輯是先排除數(shù)據(jù)和評估上的問題再去動(dòng)模型。9. 最佳實(shí)踐與工程建議9.1 實(shí)驗(yàn)記錄與版本管理比賽過程中會嘗試大量的特征組合和模型參數(shù)如果沒有實(shí)驗(yàn)記錄很容易重復(fù)試錯(cuò)白白浪費(fèi)時(shí)間。推薦用一張表格記錄每次實(shí)驗(yàn)的信息實(shí)驗(yàn)版本特征列表模型參數(shù)驗(yàn)證 AUC線上分?jǐn)?shù)備注v1 基線f_1 ~ f_20默認(rèn)參數(shù)0.82310.8204第一版v2 加統(tǒng)計(jì)特征 row_mean 等默認(rèn)參數(shù)0.83100.8277有效同時(shí)每個(gè)版本的代碼最好使用 Git 打上標(biāo)簽方便隨時(shí)回滾。9.2 模型保存與預(yù)測管理每跑完一個(gè)實(shí)驗(yàn)建議把模型、特征列表、預(yù)測結(jié)果都保存下來避免后續(xù)需要重新訓(xùn)練。import joblib # 保存模型 joblib.dump(model, model_v2.pkl) # 保存特征列表 with open(features_v2.txt, w) as f: f.write(\n.join(features)) # 加載模型 model joblib.load(model_v2.pkl)9.3 合理控制時(shí)間分配很多隊(duì)伍在比賽剛開始時(shí)花大量時(shí)間做數(shù)據(jù)可視化在后期才匆忙調(diào)參提交導(dǎo)致時(shí)間分配失衡。建議按以下節(jié)奏第一天讀取數(shù)據(jù)、建立基線、跑通提交流程。前 40% 時(shí)間特征工程。中間 30% 時(shí)間交叉驗(yàn)證、調(diào)參、模型選擇。后 30% 時(shí)間融合、閾值優(yōu)化、細(xì)節(jié)打磨。9.4 關(guān)注泛化能力而不是刷分競賽的終極目標(biāo)不是讓本地驗(yàn)證分?jǐn)?shù)最大化而是讓線上分?jǐn)?shù)盡量高且穩(wěn)定。任何時(shí)候都不要為了刷高本地分?jǐn)?shù)而做出過度擬合驗(yàn)證集的操作。常見的過度擬合行為包括反復(fù)查看驗(yàn)證集結(jié)果并針對驗(yàn)證集調(diào)參。使用過小的驗(yàn)證集導(dǎo)致結(jié)果偶然性過大。在驗(yàn)證集上做特征選擇導(dǎo)致驗(yàn)證集信息泄漏進(jìn)模型。這些行為短期看分?jǐn)?shù)很高一旦換到新的測試集上效果就會打回原形。9.5 留意數(shù)據(jù)安全與合規(guī)如果比賽數(shù)據(jù)包含用戶信息、業(yè)務(wù)敏感字段需要注意不要將數(shù)據(jù)上傳到不可信的第三方平臺。不要將數(shù)據(jù)用于比賽之外的用途。評審論文或開源代碼時(shí)避免公開原始數(shù)據(jù)。對輸出的預(yù)測結(jié)果和模型文件做好權(quán)限控制。對于生產(chǎn)環(huán)境中的數(shù)據(jù)建模更需要遵守最小權(quán)限原則只使用完成任務(wù)所必需的數(shù)據(jù)不額外采集、不保留過期數(shù)據(jù)。10. 總結(jié)與學(xué)習(xí)路線這一場比賽最大的教訓(xùn)是決定晉級的不只是模型的“上限”還有模型的“下限”。賽區(qū)一等獎(jiǎng)靠上限拿到的而國賽門檻考驗(yàn)的是你在各種意外情況下依然能夠穩(wěn)定輸出的能力。從技術(shù)角度來說這次比賽讓我重新梳理了幾個(gè)核心能力也推薦剛接觸競賽的同學(xué)按這個(gè)順序去學(xué)習(xí)和實(shí)踐掌握 pandas 和 numpy 的數(shù)據(jù)處理基本功。熟悉 LightGBM / XGBoost 的原理和常見參數(shù)。學(xué)會交叉驗(yàn)證與對抗驗(yàn)證建立起“分?jǐn)?shù)可信度”的判斷力。多做特征工程練習(xí)理解哪些特征組合能帶來真實(shí)提升。如果還有精力再深入學(xué)習(xí)模型融合和深度學(xué)習(xí)模型。今后再遇到類似的任務(wù)型建模項(xiàng)目我會先花 30 分鐘把數(shù)據(jù)分布、缺失值、標(biāo)簽比例看清楚再動(dòng)手寫模型。先確認(rèn)評估方式再談?wù){(diào)參。這份復(fù)盤如果能幫你少踩幾個(gè)坑或者在你站在國賽門檻前的時(shí)候多一分從容那就很值得了。