使用网格搜索的交叉验证返回的结果比默认值差

Posted

技术标签:

【中文标题】使用网格搜索的交叉验证返回的结果比默认值差【英文标题】:Cross validation with grid search returns worse results than default 【发布时间】:2017-09-17 18:01:29 【问题描述】:

我在 Python 中使用 scikitlearn 来运行一些基本的机器学习模型。使用内置的 GridSearchCV() 函数,我确定了不同技术的“最佳”参数,但其中许多参数的性能比默认值差。我将默认参数作为一个选项包含在内,所以我很惊讶会发生这种情况。

例如:

from sklearn import svm, grid_search
from sklearn.ensemble import GradientBoostingClassifier
gbc = GradientBoostingClassifier(verbose=1)
parameters = 'learning_rate':[0.01, 0.05, 0.1, 0.5, 1],  
              'min_samples_split':[2,5,10,20], 
              'max_depth':[2,3,5,10]
clf = grid_search.GridSearchCV(gbc, parameters)
t0 = time()
clf.fit(X_crossval, labels)
print "Gridsearch time:", round(time() - t0, 3), "s"
print clf.best_params_
# The output is: 'min_samples_split': 2, 'learning_rate': 0.01, 'max_depth': 2

这与默认值相同,除了 max_depth 为 3。当我使用这些参数时,我得到 72% 的准确度,而默认值是 78%。

我承认我做的一件事是可疑的,那就是我使用了我的整个数据集进行交叉验证。然后在获得参数后,我使用相同的数据集运行它,分成 75-25 个训练/测试。

我的网格搜索忽略了“高级”默认值有什么原因吗?

【问题讨论】:

你能详细说明你的cross_validation方案吗? @juanpa.arrivillaga 我对此很陌生,我不知道我需要用什么术语来描述它。我遵循了 scikitlearn 手册中给出的函数示例。 scikit-learn.org/stable/modules/generated/…我知道默认是三重交叉验证 【参考方案1】:

在整个数据集上运行交叉验证以进行参数和/或特征选择,当您在同一数据集上进行测试时,肯定会出现问题。看起来这至少是问题的一部分。在数据子集上运行 CV 以进行参数优化,并留下一个保留集进行测试,这是一种很好的做法。

假设您使用的是iris 数据集(即评论链接中示例中使用的数据集),下面是一个示例,说明首先使用train_test_split 设置保留集如何影响GridSearchCV 参数优化:

from sklearn import datasets
from sklearn.model_selection import GridSearchCV
from sklearn.ensemble import GradientBoostingClassifier

iris = datasets.load_iris()
gbc = GradientBoostingClassifier()
parameters = 'learning_rate':[0.01, 0.05, 0.1, 0.5, 1], 
              'min_samples_split':[2,5,10,20], 
              'max_depth':[2,3,5,10]

clf = GridSearchCV(gbc, parameters)
clf.fit(iris.data, iris.target)

print(clf.best_params_)
# 'learning_rate': 1, 'max_depth': 2, 'min_samples_split': 2

现在使用随机训练子集重复网格搜索:

from sklearn.model_selection import train_test_split

X_train,X_test,y_train,y_test = train_test_split(iris.data, iris.target, 
                                                 test_size=0.33, 
                                                 random_state=42)

clf = GridSearchCV(gbc, parameters)
clf.fit(X_train, y_train)

print(clf.best_params_)
# 'learning_rate': 0.01, 'max_depth': 5, 'min_samples_split': 2

我看到这两种方法的分类准确度要高得多,这让我觉得您可能正在使用不同的数据 - 但这里演示了在保持保留集的同时执行参数选择的基本要点。希望对您有所帮助。

【讨论】:

谢谢!就像你说的那样,即使是使用整个数据集的那个仍然显示出更高的准确性,所以我认为这是更多的东西。我最近问了一些其他问题,我的数据的另一个大问题是我没有对其进行规范化,所以这也可能导致一些问题。我会尝试所有这些建议,看看是否有所作为。【参考方案2】:

您也可以使用 Kfolds cross_validator https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.KFold.html

from sklearn import datasets
from sklearn.model_selection import GridSearchCV
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.model_selection import KFold

iris = datasets.load_iris()
gbc = GradientBoostingClassifier()
parameters = 'learning_rate':[0.01, 0.05, 0.1, 0.5, 1], 
          'min_samples_split':[2,5,10,20], 
          'max_depth':[2,3,5,10]

cv_test= KFold(n_splits=5)
clf = GridSearchCV(gbc, parameters,cv=cv_test)
clf.fit(iris.data, iris.target)

print(clf.best_params_)

【讨论】:

以上是关于使用网格搜索的交叉验证返回的结果比默认值差的主要内容,如果未能解决你的问题,请参考以下文章

在 scikit learn 中结合网格搜索和交叉验证

机器学习:交叉验证,网络搜索

对网格搜索中的所有组合使用交叉验证

我是不是需要同时执行网格搜索(使用交叉验证)和交叉验证方法?

Scikit learn 中的交叉验证与网格搜索

机器学习交叉验证和网格搜索