KNN交叉验证,找出合适的K值

在KNN里,通过交叉验证,我们即可以得出最合适的K值。它的核心思想无非就是把一些可能的K逐个去尝试一遍,然后选出效果最好的K值

交叉验证的第一步是把训练数据进一步分成训练集和验证集。

为什么这么做?

道理其实很简单,因为我们需要一种评估的机制来选出最好的K值。那具体用什么数据来评估呢? 就是验证集! 因为测试数据是用来一次性测试的。比如上线前来测试是否满足上线的条件,但测试数据不能用于指导模型的训练。

常用的交叉验证技术叫做K折交叉验证(K-fold Cross Validation)。 我们先把训练数据再分成训练集和验证集,之后使用训练集来训练模型,然后再验证集上评估模型的准确率。举个例子,比如一个模型有个参数叫alphaα,我们一开始不清楚要选择0.1还是1,所以这时候我们进行了交叉验证:把所有训练集分成K块,依次对每一个alphaα值评估它的准确率。

一般情况下数据量较少的时候我们取的K值会更大,为什么呢?

因为数据量较少的时候如果每次留出比较多的验证数据,对于训练模型本身来说是比较吃亏的,所以这时候我们尽可能使用更多的数据来训练模型。由于每次选择的验证数据量较少,这时候K折中的K值也会随之而增大,但到最后可以发现,无论K值如何选择,用来验证的样本个数都是等于总样本个数。

最极端的情况下,我们可以采用leave_one_out交叉验证,也就是每次只把一个样本当做验证数据,剩下的其他数据都当做是训练样本。

 

从零写交叉验证

1.导入模块

import numpy as np
from sklearn import datasets
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import KFold  #主要用于K折交叉验证

 

2.导入数据

# 导入iris数据集
iris=datasets.load_iris()
X=iris.data
y=iris.target
print(X.shape,y.shape)
# 定义我们想要搜索的K值(候选集),这里定义8个不同的值
ks=[1,3,5,7,9,11,13,15]

结果:

(150, 4) (150,)

3.应用

# 例:进行5折交叉验证,KFold返回的是每一折中训练数据和验证数据的index
# 假设数据样本为:[1,3,5,6,11,12,43,12,44,2],总共10个样本
# 则返回的kf的格式为(前面的是训练数据,后面的是验证数据):
# [0,1,3,5,6,7,8,9],[2,4]
# [0,1,2,4,6,7,8,9],[3,5]
# [1,2,3,4,5,6,7,8],[0,9]
# [0,1,2,3,4,5,7,9],[6,8]
# [0,2,3,4,5,6,8,9],[1,7]
kf =KFold(n_splits=5,random_state=2001,shuffle=True)

# 保存当前最好的K值和对应的准确值
best_k=ks[0]
best_score=0

# 循环每一个K值
for k in ks:
    curr_score=0
    for train_index,valid_index in kf.split(X):
        #每一折的训练以及计算准确率
        clf=KNeighborsClassifier(n_neighbors=k)
        clf.fit(X[train_index],y[train_index])
        curr_score=curr_score+clf.score(X[valid_index],y[valid_index])
    #求5折的平均准确率
    avg_score=curr_score/5
    if avg_score>best_score:
        best_k=k
        best_score=avg_score
    print("现在的最佳准确率:%.2f"%best_score,"现在的最佳K值 %d"%best_k)

print("最终最佳准确率:%.2f"%best_score,"最终的最佳K值 %d"%best_k)

结果:

现在的最佳准确率:0.96 现在的最佳K值 1
现在的最佳准确率:0.96 现在的最佳K值 1
现在的最佳准确率:0.97 现在的最佳K值 5
现在的最佳准确率:0.98 现在的最佳K值 7
现在的最佳准确率:0.98 现在的最佳K值 7
现在的最佳准确率:0.98 现在的最佳K值 7
现在的最佳准确率:0.98 现在的最佳K值 7
现在的最佳准确率:0.98 现在的最佳K值 7
最终最佳准确率:0.98 最终的最佳K值 7

 

直接使用sklearn来实现同样的逻辑,只需要调用即可以实现K折交叉验证

from sklearn import datasets
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import GridSearchCV  #通过网络方式来获取参数

# 导入iris数据集
iris2=datasets.load_iris()
X2=iris2.data
y2=iris2.target
print(X2.shape,y2.shape)

# 设置需要搜索的K值,'n_neightbors'是sklearn中KNN的参数
parameters={'n_neightbors':[1,3,5,7,9,11,13,15]}
knn=KNeighborsClassifier()#注意:这里不用指定参数

# 通过GridSearchCV来搜索最好的K值。这个模块的内部其实就是对每一个K值进行评估
clf=GridSearchCV(knn,parameters,cv=5)  #5折
clf.fit(X2,y2)

# 输出最好的参数以及对应的准确率
print("最终最佳准确率:%.2f"%clf.best_score_,"最终的最佳K值",clf.best_params_)

 

posted @ 2019-12-12 17:22  匹诺曹云  阅读(9571)  评论(0编辑  收藏  举报