我在尝试使用scikit-learn进行一些操作,并希望重现网格搜索中某个特定超参数组合的交叉验证得分。
对于网格搜索,我使用了GridSearchCV
类,而为了重现某个特定超参数组合的结果,我使用了cross_validate
函数,并使用了完全相同的分割和分类器设置。
我的问题是,我没有得到预期的得分结果,根据我的理解,这两个方法的计算方式相同,因此得分应该完全一致。
我确保在脚本中排除了任何随机源,通过固定训练数据的分割来实现这一点。
在下面的代码片段中,给出了一个所述问题的示例。
import numpy as npfrom sklearn.model_selection import cross_validate, StratifiedKFold, GridSearchCVfrom sklearn.svm import NuSVCnp.random.seed(2018)# 生成随机训练特征X = np.random.random((100, 10))# 类标签y = np.random.randint(2, size=100)clf = NuSVC(nu=0.4, gamma='auto')# 计算一个参数组合的得分grid = GridSearchCV(clf, cv=StratifiedKFold(n_splits=10, random_state=2018), param_grid={'nu': [0.4]}, scoring=['f1_macro'], refit=False)grid.fit(X, y)print(grid.cv_results_['mean_test_f1_macro'][0])# 重新计算完全相同的输入的得分result = cross_validate(clf, X, y, cv=StratifiedKFold(n_splits=10, random_state=2018), scoring=['f1_macro'])print(result['test_f1_macro'].mean())
执行给定的代码片段会得到以下输出:
0.384144688644688650.3848840048840049
我原本期望这些得分是完全相同的,因为它们是在相同的分割上,使用相同的训练数据和相同的分类器计算的。
回答:
这是因为mean_test_f1_macro
并不是所有折叠组合的简单平均值,它是一个加权平均值,权重是测试折叠的大小。要了解更多关于实际实现的信息,请参考这个答案。
现在,要复制GridSearchCV
的结果,试试这个!
print('grid search cv result',grid.cv_results_['mean_test_f1_macro'][0])# grid search cv result 0.38414468864468865print('simple mean: ', result['test_f1_macro'].mean())# simple mean: 0.3848840048840049weights= [len(test) for (_, test) in StratifiedKFold(n_splits=10, random_state=2018).split(X,y)]print('weighted mean: {}'.format(np.average(result['test_f1_macro'], axis=0, weights=weights)))# weighted mean: 0.38414468864468865