交叉验证与网格搜索得到的结果比默认设置更糟糕。

16

我正在使用Python中的Scikit-learn运行一些基本的机器学习模型。使用内置的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}

这与默认设置相同,唯一的不同在于最大深度为3。当我使用这些参数时,准确率为72%,而默认值为78%。

我做了一件事,我承认有点可疑,那就是我将整个数据集用于交叉验证。然后在获得参数后,我将其用于相同数据集拆分为75-25的训练/测试。

为什么我的网格搜索忽略了“更好”的默认值呢?


你能详细说明一下你的'交叉验证'方案吗? - juanpa.arrivillaga
@juanpa.arrivillaga 我对此还很陌生,不知道需要用什么术语来描述它。我按照scikitlearn手册中给出的函数示例进行了操作。http://scikit-learn.org/stable/modules/generated/sklearn.model_selection.GridSearchCV.html#sklearn.model_selection.GridSearchCV 我知道它默认使用三折交叉验证。 - Nicholas Hassan
2个回答

6
在整个数据集上运行交叉验证以进行参数和/或特征选择可能会在您对同一数据集进行测试时导致问题。看起来这至少是这里的部分问题。在数据子集上运行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}

我发现这两种方法的分类精度都更高,这让我想到你可能使用了不同的数据。但是,我们已经演示了在保留一组验证集的情况下进行参数选择的基本要点。希望对你有所帮助。

谢谢!就像你所说的,即使使用了整个数据集的那个模型仍然表现出更高的准确性,所以我认为这是更深层次的问题。最近我问了一些其他问题,我的数据还有一个很大的问题是我没有对其进行归一化处理,这可能也导致了一些问题。我会尝试所有这些建议,并看看是否有所改善。 - Nicholas Hassan

0

您还可以使用K折交叉验证器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_)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接