在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_)