K最近邻分类器-列车测试拆分的随机状态导致不同的准确性得分 1交叉验证 2自举 3确保测试集代表您的验证集 4获取更大的数据集

问题描述

我对数据分析和机器学习还很陌生。我已经在python的sklearn模块中对乳腺癌数据集进行了一些KNN分类分析。我有以下代码试图找到用于目标变量分类的最佳k。

from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
import matplotlib.pyplot as plt

breast_cancer_data = load_breast_cancer()

training_data,validation_data,training_labels,validation_labels = train_test_split(breast_cancer_data.data,breast_cancer_data.target,test_size = 0.2,random_state = 40)
results = []

for k in range(1,101):
  classifier = KNeighborsClassifier(n_neighbors = k)
  classifier.fit(training_data,training_labels)
  results.append(classifier.score(validation_data,validation_labels))

k_list = range(1,101)
plt.plot(k_list,results)
plt.ylim(0.85,0.99)
plt.xlabel("k")
plt.ylabel("Accuracy")
plt.title("Breast Cancer Classifier Accuracy")
plt.show()

代码循环遍历1到100,并生成100个KNN模型,其中'k'设置为介于1到100范围内的增量值。每个模型的性能都保存到列表中,并生成显示'k'的图在x轴上为',在y轴上为模型性能。

我遇到的问题是,当我将数据分为训练和测试分区时更改random_state参数时,这会导致完全不同的图,表明不同数据集分区的不同“ k”值的模型性能有所不同。

对我来说,由于算法使用不同的随机状态对不同的“ k”执行不同的操作,因此很难确定哪个“ k”是最佳的。当然,这并不意味着对于该特定数据集,“ k”是任意的?任何人都可以帮助阐明这一点吗?

感谢您的期待

Random State = 0

Random State = 40

Random State = 75

解决方法

这是完全可以预期的。进行火车测试拆分时,实际上是从原始人口中进行抽样。这意味着,当您拟合模型时,任何统计信息(例如模型参数估计或模型得分)本身都将是从某种分布中获取的样本估计。您真正想要的是在此分数附近的置信区间,而最简单的方法是重复采样并重新测量分数。

但是您必须非常小心如何执行此操作。以下是一些可靠的选项:

1。交叉验证

最常见的解决方案是使用k-fold cross-validation。为了不将该k与knn中的k混淆,我将使用大写字母进行交叉验证(但请记住,这不是正常的命名法),这是一种执行上述建议的方案,但没有目标泄漏。您无需将数据随机创建许多拆分,而是将数据拆分为K个部分(称为折叠)。然后,您每次都在K-1折数据上训练K模型,而不必像每次测试集一样设置不同的折数据。现在,每个模型都是独立的,没有目标泄漏。事实证明,您从这K个模型的K个独立测试集中使用的任何成功得分的平均值,对于使用整个集合上的那些超参数训练模型的性能都是一个很好的估计。因此,现在您应该为每个不同的k值(knn为小k)获得一个更稳定的分数,并且您可以通过这种方式选择最终的k。

一些注意事项:

  • Accuracy is a bad measure for classification performance。查看诸如精度vs召回或AUROC或f1之类的分数。
  • 不要自己尝试编写简历,请使用sklearns GridSearchCV
  • 如果您要对数据进行任何预处理以使用该数据计算某种状态,则仅需对每次折叠中的训练数据进行 即可。例如,如果要缩放数据,那么在进行缩放时就不能包含测试数据。您需要将定标器适合(并转换)到训练数据上,然后使用相同的定标器来转换您的测试数据(不再适合)。为了使它在CV中起作用,您需要使用sklearn Pipeline。这非常重要,请确保您了解它。
  • 如果根据输出类对train-test-split进行分层,则可能会获得更高的稳定性。请参见stratify上的train_test_split参数。

请注意,简历是行业标准,这是您应该做的,但是还有其他选择:

2。自举

您可以在introduction to statistical learning的5.2节(第187页)中详细了解此内容,并在5.3.4节中找到示例。

这个想法是让您训练集并替换从中抽取随机样本。这意味着您最终会得到一些重复的记录。您将采用这个新的训练集,进行训练和建模,然后在未纳入自举样本(通常称为“袋装样本”)的记录中对其评分。您重复此过程多次。现在,您可以获得分数的分布(例如准确性),可用于选择超参数,而不仅仅是以前使用的点估计。

3。确保测试集代表您的验证集

杰里米·霍华德(Jeremy Howard)对how to calibrate your validation set有一个非常有趣的建议,希望它可以很好地表示您的测试集。您只需要从该链接开始观看大约5分钟即可。想法是分成三组(无论如何,您都应该选择k等超参数),在训练集上训练一堆非常不同但简单的快速模型,然后在验证集和测试集上对其打分。可以在这里使用测试集,因为它们不是会影响最终模型的真实模型。然后绘制验证分数与测试分数。它们应该大致落在一条直线上(y = x线)。如果是这样,则意味着验证集和测试集都是好是坏,即验证集中的性能代表了测试集中的性能。如果它们不落在这条直线上,则意味着您从验证集中获得的模型得分并不表示您将从看不见的数据中获得的得分,因此您不能使用该拆分来训练明智的模型。

4。获取更大的数据集

对于您的情况,这显然不是很实际,但是我想为完整起见提及它。随着样本数量的增加,标准误会降低(即,您可以在置信区间上获得更严格的界限)。但是您将需要更多的培训和更多的测试数据。尽管您可能无法在此处使用它,但在现实世界中值得记住的是,在这种情况下,您可以评估收集新数据的成本与评估模型性能(可能还有性能本身)所需的精度之间的权衡)。

,

这种“行为”是可以预期的。当然,当培训和测试的分配方式不同时,您会得到不同的结果。

您可以通过新的Train-validation-split重复每个“ k”几次来统计地解决问题。然后取每个k的中值性能。甚至更好:查看效果分布和中位数。给定“ k”的窄性能分布也是“ k”选择得当的一个好兆头。 然后,您可以使用测试集测试模型

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...