【发布时间】:2019-03-05 20:46:42
【问题描述】:
我有一个包含 3500 个观察 x 70 个特征的数据集,这是我的训练集,我还有一个包含 600 个观察 x 70 个特征的数据集,这是我的验证集。目标是将观测值正确分类为 0 或 1。
我使用Xgboost,并在分类阈值 = 0.5 处争取尽可能高的精度。
我正在进行网格搜索:
import numpy as np
import pandas as pd
import xgboost
# Import datasets from edge node
data_train = pd.read_csv('data.csv')
data_valid = pd.read_csv('data_valid.csv')
# Specify 'data_test' as validation set for the Grid Search below
from sklearn.model_selection import PredefinedSplit
X, y, train_valid_indices = train_valid_merge(data_train, data_valid)
train_valid_merge_indices = PredefinedSplit(test_fold=train_valid_indices)
# Define my own scoring function to see
# if it is called for both the training and the validation sets
from sklearn.metrics import make_scorer
custom_scorer = make_scorer(score_func=my_precision, greater_is_better=True, needs_proba=False)
# Instantiate xgboost
from xgboost.sklearn import XGBClassifier
classifier = XGBClassifier(random_state=0)
# Small parameters' grid ONLY FOR START
# I plan to use way bigger parameters' grids
parameters = {'n_estimators': [150, 175, 200]}
# Execute grid search and retrieve the best classifier
from sklearn.model_selection import GridSearchCV
classifiers_grid = GridSearchCV(estimator=classifier, param_grid=parameters, scoring=custom_scorer,
cv=train_valid_merge_indices, refit=True, n_jobs=-1)
classifiers_grid.fit(X, y)
.................................................. ....................
train_valid_merge - 指定我自己的验证集:
我想使用我的训练集 (data_train) 对每个模型进行训练,并使用我的不同/单独验证集 (data_valid) 进行超参数调整。出于这个原因,我定义了一个名为 train_valid_merge 的函数,它将我的训练和验证集连接起来,以便可以将它们提供给 GridSeachCV,我还使用 PredefineSplit 来指定哪个是训练集,哪个是验证集这个合并集:
def train_valid_merge(data_train, data_valid):
# Set test_fold values to -1 for training observations
train_indices = [-1]*len(data_train)
# Set test_fold values to 0 for validation observations
valid_indices = [0]*len(data_valid)
# Concatenate the indices for the training and validation sets
train_valid_indices = train_indices + valid_indices
# Concatenate data_train & data_valid
import pandas as pd
data = pd.concat([data_train, data_valid], axis=0, ignore_index=True)
X = data.iloc[:, :-1].values
y = data.iloc[:, -1].values
return X, y, train_valid_indices
.................................................. ....................
custom_scorer - 指定我自己的评分指标:
我定义了我自己的评分函数,它只是返回精度只是为了查看它是否在训练集和验证集上都被调用:
def my_precision(y_true, y_predict):
# Check length of 'y_true' to see if it is the training or the validation set
print(len(y_true))
# Calculate precision
from sklearn.metrics import precision_score
precision = precision_score(y_true, y_predict, average='binary')
return precision
.................................................. ....................
当我运行整个事情(对于parameters = {'n_estimators': [150, 175, 200]})然后在my_precision 函数中从print(len(y_true)) 打印以下内容:
600
600
3500
600
3500
3500
这意味着对训练集和验证集都调用了评分函数。但是我已经测试过,评分函数不仅被调用,而且它来自训练集和验证集的结果都用于确定网格搜索中的最佳模型(即使我已经指定它只使用验证集结果)。
例如,对于我们的 3 个参数值 ('n_estimators': [150, 175, 200]),它考虑了训练集和验证集(2 集)的分数,因此它产生(3 个参数)x(2 集)= 6 个不同的网格结果。所以它从所有这些网格结果中挑选出最好的超参数集,因此它最终可能会从训练集的结果中挑选出一个,而我只想考虑验证集(3 个结果)。
但是,如果我在 my_precision 函数中添加类似的东西来规避训练集(通过将其所有精度值设置为 0):
# Remember that the training set has 3500 observations
# and the validation set 600 observations
if(len(y_true>600)):
return 0
那么(就我测试而言)我当然得到了最适合我的规格的模型,因为训练集精度结果太小了,因为它们都是 0 到。
我的问题如下:
为什么自定义评分函数会同时考虑训练和验证集来挑选最佳模型,而我已经用我的train_valid_merge_indices 指定了应该只根据验证选择网格搜索的最佳模型设置好了吗?
在完成模型的选择和排名时,如何使GridSearchCV 仅考虑验证集和模型的得分?
【问题讨论】:
-
首先,我建议您更改标题 - 因为它暗示这是问题所在,实际上这是您的要求...
-
2) 你的
train_valid_split函数又是用词不当 - 你实际上是在 合并 集合,当然不是拆分它们。不太确定您到底想在这里完成什么,或者为什么要将GridSearchCV(基于,嗯,CV)与训练/验证拆分方法混合,原则上是完全不同的... -
@desertnaut, 1) 好的,我修改了它。我希望这会更好! 2) 我只是合并数据集,以便能够在网格搜索中提供它们,并使用
PredefineSplit我指定在这个合并集中哪个是训练集,哪个是验证集。这是您可以通过GridSearchCV使用您自己的验证集的唯一方法。 -
@desertnaut,现在更清楚了吗?顺便说一句,你觉得我的要求(“只根据验证集结果挑选出最好的超参数集”)是绝对不合理的吗?
-
不仅不是不合理,而且完全是常态,像
GridSearchCV这样的函数默认是做什么的!这就是为什么我仍然很困惑为什么你在这里混合东西(即 CV 与培训/验证拆分)......
标签: python machine-learning scikit-learn cross-validation grid-search