K-nearest Neighbor Classifier 中的准确度分数与 GridSearchCV 不匹配

问题描述

我正在学习机器学习,但遇到了无法解释的不匹配问题。

我有一个网格可以根据 gridsearchcv 返回的准确度计算最佳模型。

model=sklearn.neighbors.KNeighborsClassifier()
n_neighbors=[3,4,5,6,7,8,9]
weights=['uniform','distance']
algorithm=['auto','ball_tree','kd_tree','brute']
leaf_size=[20,30,40,50]
p=[1]

param_grid = dict(n_neighbors=n_neighbors,weights=weights,algorithm=algorithm,leaf_size=leaf_size,p=p)
grid = sklearn.model_selection.gridsearchcv(estimator=model,param_grid=param_grid,cv = 5,n_jobs=1)
SGDgrid = grid.fit(data1,targetd_simp['VALUES'])
print("SGD Classifier: ")
print("Best: ")
print(SGDgrid.best_score_)
value=SGDgrid.best_score_
print("params:")
print(SGDgrid.best_params_)
print("Best estimator:")
print(SGDgrid.best_estimator_)

y_pred_train=SGDgrid.best_estimator_.predict(data1)
print(sklearn.metrics.confusion_matrix(targetd_simp['VALUES'],y_pred_train))
print(sklearn.metrics.accuracy_score(targetd_simp['VALUES'],y_pred_train))

我得到的结果如下:

SGD Classifier:
Best:
0.38694539229180525
params:
{'algorithm': 'auto','leaf_size': 20,'n_neighbors': 8,'p': 1,'weights': 'distance'}
Best estimator:
KNeighborsClassifier(leaf_size=20,n_neighbors=8,p=1,weights='distance')
[[4962    0    0]
 [   0 4802    0]
 [   0    0 4853]]
1.0

可能这个模型高度过拟合。我仍然要检查它,但这不是问题的问题。

所以,基本上,如果我理解正确,gridsearchcv 正在为交叉验证中的一个块找到 0.3869(相当差)的最佳准确度分数,但最终的混淆矩阵是完美的,以及它的准确度最终矩阵。这对我来说没有多大意义......理论上如此糟糕的模型表现如何?

我还在 gridsearchcv添加scoring = 'accuracy' 以确保返回的值实际上是准确的,并且返回的值完全相同。

在这里遗漏了什么?

解决方法

您所描述的行为很正常,在意料之中。您应该知道 GridSearchCV 有一个默认设置为 true 的参数 refit。它触发以下内容:

使用在整个数据集上找到的最佳参数重新拟合估计器。

这意味着 best_estimator_ 返回的估算器已针对您的整个数据集(在您的情况下为 data1)进行了改装。因此,估计器在训练期间已经看到了数据,并且预期在其上表现得特别好。您可以使用以下示例轻松重现这一点:

from sklearn.datasets import make_classification
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split,GridSearchCV
from sklearn.neighbors import KNeighborsClassifier


X,y = make_classification(random_state=7)
X_train,X_test,y_train,y_test = train_test_split(X,y,random_state=42)

search = GridSearchCV(KNeighborsClassifier(),param_grid={'n_neighbors': [3,4,5]})
search.fit(X_train,y_train)

print(search.best_score_)

>>> 0.8533333333333333

print(accuracy_score(y_train,search.predict(X_train)))

>>> 0.9066666666666666

虽然这不像你的情况那么令人印象深刻,但它仍然是一个明确的结果。在交叉验证期间,模型针对未用于训练模型的一个折叠进行验证,因此针对模型之前未见过的数据进行验证。然而,在第二种情况下,模型在训练期间已经看到了所有数据,预计模型在这些数据上的表现会更好。

为了更好地感受真实的模型性能,您应该使用包含模型之前未见过的数据的保持集:

print(accuracy_score(y_test,search.predict(X_test)))

>>> 0.76

如您所见,该模型在这些数据上的表现要差得多,并向我们表明以前的指标都有些过于乐观了。该模型实际上并没有很好地概括。

总而言之,您的结果并不令人惊讶,并且有一个简单的解释。分数的高差异令人印象深刻,但仍然遵循相同的逻辑,实际上只是过度拟合的明确指标。