KNeighborsClassifier k=1时交叉验证返回完美准确率是否存在Bug?
问题原因说明
这不是KNeighborsClassifier的已知Bug,是你模型评估的逻辑错误导致的:
- k=1的K近邻算法本身的特性就是:训练阶段会直接记忆所有训练样本,预测时会取距离目标样本最近的1个样本的标签作为预测结果。当你预测的样本就是训练集本身的样本时,每个样本的最近邻就是它自己,预测结果必然和真实标签完全一致,因此F1分数固定为1,该结果和交叉验证参数
cv的取值无关,哪怕输入随机数据集也会得到相同结果,属于算法的正常表现。 - 你代码中的错误在于:用全量数据集
X_df完成模型训练后,仍然用同一个X_df作为预测输入,相当于用已经做过的原题测试模型,自然会得到满分的错误评估结果。 GridSearchCV中的cv参数仅用于交叉验证阶段评估超参数的泛化性能,不会影响最终训练得到的最优 estimator 的预测逻辑,你如果要获取合理的模型性能评分,有两种常用方案:- 提前拆分独立的测试集,模型仅在训练集上拟合,最终用测试集做预测再计算评估指标
- 直接取
GridSearchCV输出的交叉验证验证集平均得分,该得分已经排除了训练集数据泄露的影响
正确代码示例
from sklearn.model_selection import train_test_split from sklearn.neighbors import KNeighborsClassifier from sklearn.model_selection import GridSearchCV from sklearn.metrics import confusion_matrix # 第一步:拆分独立训练集、测试集,测试集不参与训练过程 X_train, X_test, y_train, y_test = train_test_split(X_df, y_df, test_size=0.3, random_state=42) k=1 param_space = {'n_neighbors': [k]} model = KNeighborsClassifier(n_neighbors=k, metric='euclidean') search = GridSearchCV(model, param_space, cv=4, verbose=10, n_jobs=8) search.fit(X_train, y_train) # 方案1:用独立测试集评估性能 preds = search.best_estimator_.predict(X_test) tn, fp, fn, tp = confusion_matrix(y_test, preds).ravel() f1 = tp / (tp + 0.5 * (fp + fn)) # 方案2:直接取交叉验证的验证集平均得分 cv_f1 = search.cv_results_['mean_test_score'].mean()
修改后评估得到的F1分数就不会再固定为1,可以正常反映模型的泛化性能。
内容的提问来源于stack exchange,提问作者Netanel
相关产品推荐
相关产品推荐

