使用网格搜索进行交叉验证 returns 结果比默认值差

Cross validation with grid search returns worse results than default

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

例如:

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 training/testing.

我的网格搜索忽略了 "superior" 默认值是什么原因?

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

假设您使用的是 iris dataset (that's the dataset used in the example in your comment link), here's an example of how GridSearchCV parameter optimization is affected by first making a holdout set with train_test_split

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}

我发现这两种方法都有更高的分类准确率,这让我觉得您可能使用了不同的数据 - 但此处演示了在保持保留集的同时执行参数选择的基本要点。希望对你有帮助。

您也可以使用 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_)