为什么我的 KNeighborsClassifier 图看起来像这样?

数据挖掘 机器学习 分类 scikit-学习 k-nn
2022-02-17 11:45:26

我是数据科学/ml 的新手,正在使用 sklearn 库对数据进行分类。我目前正在使用具有 5 折交叉验证的 KNeighborsClassifier,同时调整 k 值,但它生成的图形看起来很奇怪。

我在 2 个不同的 CSV 文件中有我的训练数据和测试数据,并像这样加载它们:

trainData = pd.read_csv('train.csv',header='infer')
testData = pd.read_csv('test.csv',header='infer')

然后我分离分类器(Y 是我的数据集中作为分类的列的名称):

trainY = trainData['Y']
trainX = trainData.drop(['Y'],axis=1)

testY = testData['Y']
testX = testData.drop(['Y'],axis=1)

我使用 sklearn KNeighborsClassifier 进行 5 折交叉验证,同时将 k 值从 2 调整到 20:

trainAcc = []
testAcc = []

for i in range(2,20):
    clf = KNeighborsClassifier(n_neighbors=i, metric='minkowski', p=2)
    trainScores = cross_val_score(estimator=clf, X=trainX, y=trainY, cv=5, n_jobs=4)
    testScores= cross_val_score(estimator=clf, X=testX, y=testY, cv=5, n_jobs=4)
    trainAcc.append((i, trainScores.mean()))
    testAcc.append((i, testScores.mean()))

然后我打印图表:

plt.plot([x[0] for x in trainAcc],[x[1] for x in trainAcc], 'ro-', [x[0] for x in testAcc],[x[1] for x in testAcc], 'bv--')

但是我得到了一些奇怪的东西:

在此处输入图像描述

谁能解释我哪里出错了,为什么我的图表看起来像这样。

谢谢。

编辑:这确实很奇怪,因为当我在进行交叉验证的情况下运行它时,我会得到一个更正常的图表,如下所示:

clf.fit(X=trainX, y=trainY)
predTrainY = clf.predict(trainX)
predTestY = clf.predict(testX)
trainAcc.append(accuracy_score(trainY, predTrainY))
testAcc.append(accuracy_score(testY, predTestY))

在此处输入图像描述

3个回答

从评论线程中总结:这里发生了两件“奇怪”的事情。

1.之字形。

正如我在评论中和@BrianSpiering 在回答中所说的那样,这可能是一种平价效应,是由于最近邻居之间的票数相同而引起的k甚至。

2. 训练准确率不会随着增加而降低(朝向测试准确率)k.

这是由于不正确使用cross_val_score. 您在训练集和测试集上分别运行了该函数两次。但这意味着您的结果是训练集上的非折叠分数(不是实际的训练分数!),以及来自测试集(折叠)上拟合的模型的分数(不是来自训练模型的测试集的分数在训练集上)。

可能最干净的方法是使用GridSearchCV搜索不同的值k. 然后,您可以从中提取结果cv_results_以进行绘图。否则,如果您不需要它们用于其他任何事情,您可以删除交叉验证(只需在训练和测试集上得分)或测试集(只需进行交叉验证并在训练和测试折叠上获得分数)。

一种解释是,当 k 为偶数时,该模型具有较高的准确性。KNeighborsClassifier 中的偶数组可能会导致大量的关联(即,模型预测数据点同样可能属于多个组)。当 k 为奇数时,该模型的准确性降低,当 k 为奇数时,平局不太可能发生。

查看原始数据的性能可能会有所帮助。特别是当模型正确和模型错误时。

您可以尝试使用相同的 k,例如 k=8 并运行您的交叉验证模型 100 次,也许每次运行的采样会有一些变化,并绘制每次运行的结果,看看是否会有一些曲折之间运行。也许您的数据有很多情况,例如距离函数的权重对于两个候选者(甚至更多)是相同的,但由于 k 的限制,您只能选择一个。您可以尝试为此类场景找到更好的距离函数,例如允许拥有不同大小的集群k=x+{1,1,0}