自定义交叉验证的样本划分方法¶
交叉验证是缓解模型过拟合的手段之一。本文以 XGBoost 算法为例,介绍了如何自定义交叉验证中划分训练集和验证集的方法。
方法 1:在folds
中传入自定义的训练集和测试集的索引¶
Python
import pandas as pd
import numpy as np
from sklearn.model_selection import TimeSeriesSplit
from xgboost import XGBClassifier
import xgboost as xgb
关于交叉验证中的folds
参数,官方文档是这样写的:
Text Only
folds : a KFold or StratifiedKFold instance or list of fold indices
Sklearn KFolds or StratifiedKFolds object.
Alternatively may explicitly pass sample indices for each fold.
For ``n`` folds, **folds** should be a length ``n`` list of tuples.
Each tuple is ``(in,out)`` where ``in`` is a list of indices to be used
as the training samples for the ``n`` th fold and ``out`` is a list of
indices to be used as the testing samples for the ``n`` th fold.
因此,我们可以自定义训练集和测试集的索引,它实际上是一个列表,列表中的元素是二元 tuple,每个 tuple 中存放([训练集的索引], [验证集的索引])
,然后传入 folds 中。
更多例子,可以参考这篇帖子。
Python
# 定义空列表,用于存储交叉验证选取的训练集和验证集的索引
folds_data = []
# 使用时序交叉验证方法
cv = TimeSeriesSplit(n_splits=2)
# 将 train 进一步划分为训练集和验证集
for train_index, validation_index in cv.split(x_train):
# 将训练集和验证集的索引存储到 folds_data 中
folds_data.append((train_index, validation_index))
在上一段代码中,我们构造了folds_data
,它实际上只是将TimeSeriesSplit(n_splits=2)
划分的训练集和验证集的索引存储了起来。如果我们想要高度地定制化训练集和验证集的索引,也可以不用现成的TimeSeriesSplit
等Split
方法,而是自己设定train_index
和validation_index
。
在folds
中传入自定义的训练集和测试集的索引:
Python
# 交叉验证
# 设定本次交叉验证使用的模型参数
xgb_clf = XGBClassifier(
max_depth=3, eta=0.1, n_estimators=5000, gamma=0, min_child_weight=1
)
# 储存本次交叉验证的结果
cv_results = xgb.cv(
params=xgb_clf.get_xgb_params(),
dtrain=xgb.DMatrix(x_train, y_train),
num_boost_round=1000,
nfold=len(folds_data),
folds=folds_data, # 这里传入的是训练集和验证集的索引元组构成的列表
metrics="auc",
early_stopping_rounds=5, # 如果连续 5 轮迭代后 test-auc 值没有比之前的最大值有所提升,则停止训练
verbose_eval=True,
show_stdv=True,
seed=0,
)
这样就完成了一次交叉验证,得到的结果就是:给定参数下,在各个验证集下的评价指标的均值。
方法 2:直接传入一个交叉验证对象的实例¶
这个方法比较简单。如果不需要在默认划分方法上做修改的话,更推荐使用这个方法,并且得到的结果和方法 1 是一模一样的。
Python
# 使用时序交叉验证方法,将 gram_train 划分为训练集和验证集
cv = TimeSeriesSplit(n_splits=2)
# 交叉验证
# 设定本次交叉验证使用的模型参数
xgb_clf = XGBClassifier(
max_depth=3, eta=0.1, n_estimators=5000, gamma=0, min_child_weight=1
)
# 储存本次交叉验证的结果
cv_results = xgb.cv(
params=xgb_clf.get_xgb_params(),
dtrain=xgb.DMatrix(gram_train, train["Label"].values),
num_boost_round=1000,
nfold=len(folds_data),
folds=cv, # 这里直接使用 cv,在之前定义的一个 TimeSeriesSplit 对象的实例
metrics="auc",
early_stopping_rounds=5, # 如果连续 5 轮迭代后 test-auc 值没有比之前的最大值有所提升,则停止训练
verbose_eval=True,
show_stdv=True,
seed=0,
)