【笔记】验证数据集与交叉验证
验证数据集与交叉验证
一些相关前提:
验证数据集
严格意义上来说,使用训练数据集和测试数据集来进行是有不太好的地方,这样得出来的模型,可能导致一个问题,即这个最后得到的模型是过拟合了这个特定的测试数据集
不断的调参再去训练数据集重新得到模型在进行测试数据,最后找到一组参数使模型在测试数据集上效果最好,这样就使得这个模型始终围绕着这个测试数据,由于测试数据集是已知的,那么这就相当于针对这组测试数据集进行调参,这有可能出现过拟合的情况
那么要想解决这个情况,就可以将其分成三部分,即
训练数据集(训练模型)
验证数据集(测试好数据以后,将验证数据送入模型看一下效果是咋样的,效果不好的话就调参,重新训练模型,这就使得模型针对验证模型达到最优,即其为调整超参数使用的数据集)
测试数据集(在模型已经针对验证数据得到最优以后再传入模型,其作为衡量最终模型性能的数据集,其并没有参与模型的创建,其对于模型是完全不可知的)
这样得到的模型的结果是更加准确的,但是这样操作以后还有一个问题,即由于验证数据集是从原先的数据集中随机的切出来的,那么这个模型就有可能过拟合这个验证数据集,一旦这一份验证数据集里面的数据不好,比如存在极端数据的话,这就使得模型不准确,为了解决这个问题,就有了交叉验证
交叉验证
那么什么是交叉验证呢?
交叉验证,其是比较正规的在调参的时候使用的观察模型性能的方式
对于训练的数据来说,通常将其分为k份,那么就可以让这k份数据分别作为验证数据集,比如有三份,为abc,就可以分为以bc为训练数据集,a为验证数据集,以ac为训练数据集,b为验证数据集以及以ab为训练数据集,c为验证数据集,这样的对应的搭配就会产生三个模型,这三个模型每一个模型在验证数据集上都会求出来一个性能的指标,这几个指标的平均就作为当前算法的指标,即将这k个模型的均值作为结果调参
具体实现一下
(在notebook中)
使用书写识别数据
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
digits = datasets.load_digits()
X = digits.data
y = digits.target
这里还是将数据集分成训练数据集和测试数据集
from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.4,random_state=666)
这里使用knn这个方法来对手写数据进行识别,在过程中要不断地进行调参,一共有两个参数,分别为k和p,对k来说,从2到10之间不断选择,对p来说,从1到5之间进行选择,每一次都传knn_clf调用KNeighborsClassifier这个构造函数,传入weights="distance",n_neighbors=k,p=p,然后计算得到score,将其存起来,如果这个score是大于历史上所找到的最好的score,这样就要将当前的score,k,p给记录下来,循环得出最佳的k和p,然后打印出来
from sklearn.neighbors import KNeighborsClassifier
best_score,best_p,best_k = 0,0,0
for k in range(2,11):
for p in range(1,6):
knn_clf = KNeighborsClassifier(weights="distance",n_neighbors=k,p=p)
knn_clf.fit(X_train,y_train)
score = knn_clf.score(X_test,y_test)
if score > best_score:
best_score,best_p,best_k = score,p,k
print("Best k =",best_k)
print("Best p =",best_p)
print("Best Score =",best_score)
结果如下
这里就是用交叉验证的方法来进行超参数的调整
使用sklearn中的cross_val_score,只要传入算法和相应的X_train,y_train,就会自动进行交叉验证的过程,同时返回每个模型对应的准确率
from sklearn.model_selection import cross_val_score
knn_clf = KNeighborsClassifier()
cross_val_score(knn_clf,X_train,y_train)
结果如下(为啥我是五个值,就挺突然的,或许是默认为5?不过过程是对的,后续结果也会也能出现偏差)
调参的逻辑和上面的差不多,不同的是每次要调用cross_val_score的方法计算,scores = cross_val_score(knn_clf,X_train,y_train),这样一来就是用了交叉验证的结果
best_score,best_p,best_k = 0,0,0
for k in range(2,11):
for p in range(1,6):
knn_clf = KNeighborsClassifier(weights="distance",n_neighbors=k,p=p)
scores = cross_val_score(knn_clf,X_train,y_train)
score = np.mean(scores)
if score > best_score:
best_score,best_p,best_k = score,p,k
print("Best k =",best_k)
print("Best p =",best_p)
print("Best Score =",best_score)
结果如下
这样我们拿到了最佳的参数,这是就是用找到的最佳的参数来进行分类,然后使用test来计算准确度
best_knn_clf = KNeighborsClassifier(weights="distance",n_neighbors=2,p=2)
best_knn_clf.fit(X_train,y_train)
best_knn_clf.score(X_test,y_test)
结果如下
实际上这个过程是网格搜索中是有进行的,使用的sklearn中的GridSearchCV,GridSearchCV中的CV就是交叉验证的意思
详细过程:
from sklearn.model_selection import GridSearchCV
param_grid = [
{
'weights':['distance'],
'n_neighbors':[i for i in range(2,11)],
'p': [i for i in range(1,6)]
}
]
grid_search = GridSearchCV(knn_clf, param_grid,verbose=1)
grid_search.fit(X_train,y_train)
结果如下
使用以下代码就可以发现对应的结果了,和上述的结果相同,不再赘述
grid_search.best_score_
grid_search.best_params_
best_knn_clf = grid_search.best_estimator_
best_knn_clf.score(X_test,y_test)
还可以对交叉验证设置cv为5,使其分成五份
cross_val_score(knn_clf,X_train,y_train,cv=5)
结果为
同理网格搜索也是可以设置cv
GridSearchCV(knn_clf,param_grid,verbose=1,cv=5)
结果为
我们一般称上面的为称为k-folds交叉验证,其也是有缺点的,由于分成了k份数据,每次训练k个模型,整体的性能肯定是会慢很多的
在极端情况下,k-folds交叉验证可以变成留一法LOO-CV的交叉验证方式,其就是训练数据集有m个样本,就把训练数据集分成m份,即每次都将m-1份样本去训练,然后去预测剩下的的一个样本,将这些结果平均,这样做将完全不受随机的影响,最接近模型真正的性能指标,但是很明显,计算量巨大