什么是交叉驗證?
交叉驗證是一種將原始數據集劃分為若干個子集,反復訓練和驗證模型的策略。
交叉驗證(Cross-Validation)適用于你在模型調參(如邏輯回歸中的 C
)
最常用的:K 折交叉驗證(K-Fold Cross Validation)
將數據集平均分成 K 份,每次取其中 1 份做驗證,剩下的 K-1 份做訓練,重復 K 次,最終將 K 次的結果取平均。
圖示流程(以 K=4 舉例)
輪次 | 訓練集 | 驗證集 |
---|---|---|
1 | [2,3,4] | [1] |
2 | [1,3,4] | [2] |
3 | [1,2,4] | [3] |
4 | [1,2,3] | [4] |
最后將 4 次的驗證結果平均,得到模型在未見數據上的穩定表現。
為什么要使用交叉驗證?
作用 | 說明 |
---|---|
? 穩定評估模型表現 | 解決只依賴單一測試集帶來的評估波動問題 |
? 防止過擬合 | 多次訓練驗證,有助于檢測模型是否泛化能力不足 |
? 用于超參數選擇 | 常用于網格搜索、正則化參數調優(如邏輯回歸中的 C) |
什么時候該用交叉驗證?
場景 | 是否推薦使用交叉驗證 |
---|---|
數據量較小 | ? 強烈建議 |
不平衡分類問題 | ? 建議配合 StratifiedKFold |
模型調參(如 C、k、深度) | ? 必用 |
數據量極大(上百萬) | ? 考慮分批驗證或子集評估 |
代碼使用:
from sklearn.model_selection import cross_val_scorecross_val_score(estimator, X, y=None, *, scoring=None, cv=None,n_jobs=None, verbose=0, fit_params=None, pre_dispatch='2*n_jobs',error_score=np.nan)
參數詳解:
參數名 | 類型 | 說明 |
---|---|---|
estimator | 模型對象 | 要評估的模型,例如 ‘model = LogisticRegression()’后直接傳入‘model’即可 |
X | ndarray / DataFrame | 特征數據集 |
y | array-like | 目標標簽(監督學習必須) |
scoring | str 或 callable | 指定評估指標(如 accuracy , recall , f1 , roc_auc 等) |
cv | int 或 交叉驗證對象 | 交叉驗證折數,如 cv=5 ;或 StratifiedKFold , KFold 等對象 |
n_jobs | int | 并行執行的任務數:-1 使用所有核心,1 表示不并行 |
verbose | int | 控制打印的詳細程度(0為不輸出,越大越詳細) |
fit_params | dict | 要傳遞給 estimator.fit() 的額外參數(少用) |
pre_dispatch | str | 控制預分發任務數,默認 '2*n_jobs' ,通常無需改動 |
error_score | ‘raise’ 或 float | 出錯時返回分數,或拋異常。默認返回 NaN |
實戰案例:用交叉驗證尋找最優懲罰因子 C
信用卡欺詐檢測數據集?creditcard.csv
-
數據來源信用卡欺詐檢測實戰數據集_數據集-阿里云天池
https://tianchi.aliyun.com/dataset/101562?accounttraceid=c1258603818f44d6a57fe125248cc969rkgu
-
樣本總數:284,807 條
-
特征數:30(28個匿名特征 + 金額
Amount
+ 時間Time
) -
目標變量:
Class
(0=正常交易,1=欺詐交易)
import numpy as np
import pandas as pd
from sklearn.linear_model import LogisticRegression # 導入邏輯回歸模型
from sklearn.model_selection import train_test_split, cross_val_score # 用于數據拆分和交叉驗證
from sklearn.preprocessing import StandardScaler # 用于數據標準化處理
from sklearn import metrics # 用于模型評估指標計算data = pd.read_csv('creditcard.csv')# 初始化標準化器,對交易金額(Amount)進行標準化處理
scaler = StandardScaler()
data['Amount'] = scaler.fit_transform(data[['Amount']]) # 準備特征數據X(排除時間和目標變量)和目標變量y(欺詐標簽,1表示欺詐,0表示正常)
X = data.drop(["Time","Class"], axis=1)
y = data.Class# 將數據拆分為訓練集(70%)和測試集(30%),設置隨機種子保證結果可復現
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=100)#----------------------------------------------------------------------------------------
# 以下部分用于尋找最優的正則化參數C
c_range = [0.01, 0.1, 1, 10, 100] # 定義要嘗試的正則化參數C的取值范圍(C越小,正則化強度越大)
scores = [] # 存儲不同C值對應的交叉驗證平均召回率
for c in c_range:model = LogisticRegression(C=c, penalty='l2', solver='lbfgs', max_iter=1000) # 初始化邏輯回歸模型,指定正則化參數C、L2正則化、求解器和最大迭代次數score = cross_val_score(model, X_train, y_train, cv=8, scoring='recall') # 使用8折交叉驗證,計算模型在訓練集上的召回率recallscore_mean = sum(score) / len(score) # 計算交叉驗證召回率的平均值scores.append(score_mean) # 將平均召回率添加到列表中print(score_mean)
# 找到最大平均召回率對應的C值,作為最優懲罰因子
best_c = c_range[np.argmax(scores)] #argmax返回數組中最大值所在的索引位置
print(f'最優懲罰因子為:{best_c}')
#----------------------------------------------------------------------------------------# 使用最優懲罰因子訓練最終的邏輯回歸模型
model = LogisticRegression(C=best_c, penalty='l2', solver='lbfgs')
model.fit(X_train, y_train)
K-Fold Cross Validation 背后的原理(做了什么)
cross_val_score(model, X, y, cv=8)
等價于以下操作:
-
將數據按 8?等份分割
-
第一次拿前 7?份訓練,第 8?份驗證 → 計算指標
-
第二次拿 1,2,3,4,5,6,8 訓練,第 7?份驗證 → 計算指標
-
...
-
得到 8?個指標結果,返回組成數組
它自動完成了分割、訓練、預測和評分!
常見擴展:StratifiedKFold(保持類別比例)
對于不平衡數據(如欺詐檢測),StratifiedKFold
是更合適的選擇,它能在每一折中保持正負樣本比例一致。
from sklearn.model_selection import StratifiedKFoldskf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
scores = cross_val_score(model, X_train, y_train, cv=skf, scoring='recall')