为啥随机搜索显示比网格搜索更好的结果?

Posted

技术标签:

【中文标题】为啥随机搜索显示比网格搜索更好的结果?【英文标题】:Why is Random Search showing better results than Grid Search?为什么随机搜索显示比网格搜索更好的结果? 【发布时间】:2018-06-14 15:47:23 【问题描述】:

我正在使用 scikit-learn 的 RandomizedSearchCV 函数。一些学术论文声称,与整个网格搜索相比,随机搜索可以提供“足够好”的结果,但可以节省大量时间。

令人惊讶的是,有一次,RandomizedSearchCV 为我提供了比 GridSearchCV 更好的结果。我认为 GridSearchCV 应该是详尽无遗的,所以结果必须比 RandomizedSearchCV 更好(假设它们通过相同的网格搜索)。

对于相同的数据集和大部分相同的设置,GridsearchCV 向我返回了以下结果: 最佳 cv 准确度:0.7642857142857142 测试集分数:0.725 最佳参数:'C':0.02

RandomizedSearchCV 向我返回了以下结果: 最佳 cv 准确度:0.7428571428571429 测试集分数:0.7333333333333333 最佳参数:'C':0.008

对我来说,0.733 的测试分数比 0.725 好,而且 RandomizedSearchCV 的测试分数和训练分数之间的差异更小,据我所知,这意味着更少的过拟合。

那么为什么 GridSearchCV 返回的结果更差?

GridSearchCV 代码:

def linear_SVC(x, y, param, kfold):
    param_grid = 'C':param
    k = KFold(n_splits=kfold, shuffle=True, random_state=0)
    grid = GridSearchCV(LinearSVC(), param_grid=param_grid, cv=k, n_jobs=4, verbose=1)

    return grid.fit(x, y)

#high C means more chance of overfitting

start = timer()
param = [i/1000 for i in range(1,1000)]
param1 = [i for i in range(1,101)]
param.extend(param1)

#progress = progressbar.bar.ProgressBar()
clf = linear_SVC(x=x_train, y=y_train, param=param, kfold=3)

print('LinearSVC:')
print('Best cv accuracy: ' .format(clf.best_score_))
print('Test set score:   ' .format(clf.score(x_test, y_test)))
print('Best parameters:  ' .format(clf.best_params_))
print()

duration = timer() - start
print('time to run: ' .format(duration))

RandomizedSearchCV 代码:

from sklearn.model_selection import RandomizedSearchCV

def Linear_SVC_Rand(x, y, param, kfold, n):
    param_grid = 'C':param
    k = StratifiedKFold(n_splits=kfold, shuffle=True, random_state=0)
    randsearch = RandomizedSearchCV(LinearSVC(), param_distributions=param_grid, cv=k, n_jobs=4,
                                    verbose=1, n_iter=n)

    return randsearch.fit(x, y)

start = timer()
param = [i/1000 for i in range(1,1000)]
param1 = [i for i in range(1,101)]
param.extend(param1)

#progress = progressbar.bar.ProgressBar()
clf = Linear_SVC_Rand(x=x_train, y=y_train, param=param, kfold=3, n=100)

print('LinearSVC:')
print('Best cv accuracy: ' .format(clf.best_score_))
print('Test set score:   ' .format(clf.score(x_test, y_test)))
print('Best parameters:  ' .format(clf.best_params_))
print()

duration = timer() - start
print('time to run: ' .format(duration))

【问题讨论】:

您知道您在 GridSearchCV 中使用 KFold,在 RandomizedSearchCV 中使用 StratifiedKFold?你知道它们每次都会产生不同的折叠吗? 此外,您应该使用相同的 random_state 变量创建 LinearSVC,以确保可重现性 我以为随机状态已经设置好了。你的意思是我需要为 LinearSVC 本身设置另一个? 【参考方案1】:

首先,试着理解这一点: https://stats.stackexchange.com/questions/49540/understanding-stratified-cross-validation

所以你应该知道 StratifiedKFold 比 KFold 更好。

在 GridSearchCV 和 RandomizedSearchCV 中使用 StratifiedKFold。确保设置“shuffle = False”而不使用“random_state”参数。这是做什么的:您正在使用的数据集不会被打乱,因此每次训练时您的结果都不会改变。你可能会得到你所期望的。

GridSearchCV 代码:

def linear_SVC(x, y, param, kfold):
    param_grid = 'C':param
    k = StratifiedKFold(n_splits=kfold)
    grid = GridSearchCV(LinearSVC(), param_grid=param_grid, cv=k, n_jobs=4, verbose=1)

    return grid.fit(x, y)

RandomizedSearchCV 代码:

def Linear_SVC_Rand(x, y, param, kfold, n):
    param_grid = 'C':param
    k = StratifiedKFold(n_splits=kfold)
    randsearch = RandomizedSearchCV(LinearSVC(), param_distributions=param_grid, cv=k, n_jobs=4,
                                    verbose=1, n_iter=n)

    return randsearch.fit(x, y)

【讨论】:

非常感谢您回答我的问题。我现在明白为什么我会得到不一致的结果。 你可以直接使用cv=kfold,如文档中所述:cv:-integer,指定(分层)KFold中的折叠数,【参考方案2】:

从它看起来运行正常的情况来看。您在网格搜索中的训练/简历集精度高于随机搜索中的训练/简历集精度。超参数不应使用测试集进行调整,因此假设您正确执行此操作,可能只是巧合,从随机搜索中选择的超参数在测试集上表现更好。

【讨论】:

以上是关于为啥随机搜索显示比网格搜索更好的结果?的主要内容,如果未能解决你的问题,请参考以下文章

Lesson 10.1 超参数优化与枚举网格的理论极限和随机网格搜索 RandomSearchCV

Lesson 9.3 集成算法的参数空间与网格优化和使用网格搜索在随机森林上进行调参

调参-网格搜索(Grid Search)

超参数估计的随机搜索和网格搜索的比较

Sklearn超参调优手段:网格搜索(Grid Search)和随机搜索(Randomized Search)

Sklearn超参调优手段:网格搜索(Grid Search)和随机搜索(Randomized Search)