1. 程式人生 > >機器學習:交叉驗證和模型選擇與Python程式碼實現

機器學習:交叉驗證和模型選擇與Python程式碼實現

前言:本篇博文主要介紹交叉驗證(cross validation)和模型選擇,首先介紹相關的基礎概念和原理,然後通過Python程式碼實現交叉驗證和模型評估以及選擇。特別強調,其中大多理論知識來源於《統計學習方法_李航》斯坦福課程翻譯筆記

1.分類器的評價

評價分類器效能的指標一般是分類的準確率,其定義是:對於給定的測試資料集(X_test),分類器正確分類的樣本數與總樣本數之比。

這裡特別強調一下,有一種分類問題——“偏斜分類”——一般是“二分類”問題。這類問題有一個特點就是:某一類的樣本數很少,例如病患者中的癌症患者(假如只佔了0.5%),那麼我現在不需要什麼高階演算法,只需要對任何人說,“你沒癌症”,那麼我的正確率理論上都達到了99.5%,所以他不適合簡單的計算準確率,而是所謂的“精確率”(precision)和“召回率”(recall)的調和均值:F1 score。(這裡不介紹,詳情請看前言部分提供的

電子書)。

2.分類器的選擇

前面的knn演算法中提到過,knn分類器裡面的K值到底設定多少才是合適的?還有knn演算法中,距離函式到底該選擇L1範數還是L2範數?當然,可能還有其他需要考慮的選擇我們沒考慮到。所有這些引數的選擇,我們稱之為“超引數”(hyperparameter)。

我們一般建議,嘗試不同的值,也就是嘗試不同的演算法,看看哪個演算法的效能最好?但是這裡有一點需要特別注意!!!!——我們決不能使用測試集(X_test)來進行引數和模型調優。為什麼這麼說呢,因為如果你用測試集調優,就相當於你用測試集評價挑選出來的最優演算法,然後再用測試集來評價,那效果肯定還是最好。但是一旦遇到實際的資料,往往效果就不理想,這稱之為“過擬合”(隨後聊)。

總之,記住,“測試集”(X_test)只能在最後一次模型評價中使用!

那麼,就有了下面的“交叉驗證”!

3.交叉驗證

一般,如果給定的樣本資料充足,我們會隨機的從“訓練集”(X_train)中提取一部分資料來調優,這個資料集叫做“驗證集”(X_validation)。

但是,如果資料不充足,我們往往採用“交叉驗證”的方法——把給定的資料進行切分(例如分成5段),將切分的資料集分為“訓練集”和“驗證集”(假設其中4份為train,1份為validation),在此基礎上迴圈選取(4份為train,1份為validation),進行訓練和驗證。從而選擇其中最好的模型。

ps:實際運用中,因為交叉驗證會耗費較多的計算資源(畢竟一直迴圈選取,然後訓練,驗證)。所以一般資料充足,直接隨機

選取一小部分作為“驗證集”就行了。(tips:一定要隨機,因為如果原來的資料集排列有一定的規律,例如前100全是A類,後100全是B類,那麼你只是簡單的用語句X_val = X[150:],得到的就只有B類了。當然,如果樣本本來就是隨機分佈的,那就沒關係。)

4.交叉驗證與模型選擇Python程式碼實現

不多說,上程式碼,寫的累啊~

首先看看資料集,這是一種花的資料集

import numpy as np
from sklearn.datasets import load_iris
import matplotlib.pyplot as plt

#load datasets
iris = load_iris()
data = iris.data[:,:2]
target = iris.target
print data.shape#(150,2)
print data[:10]
print target[:10]

label = np.array(target)
index_0 = np.where(label==0)
plt.scatter(data[index_0,0],data[index_0,1],marker='x',color = 'b',label = '0',s = 15)
index_1 =np.where(label==1)
plt.scatter(data[index_1,0],data[index_1,1],marker='o',color = 'r',label = '1',s = 15)
index_2 =np.where(label==2)
plt.scatter(data[index_2,0],data[index_2,1],marker='s',color = 'g',label = '2',s = 15)
plt.xlabel('X1')
plt.ylabel('X2')
plt.legend(loc = 'upper left')
plt.show()
上面程式碼為了方便視覺化,只是選取了兩種特徵,執行如下:


接著隨機抽取一部分作為“測試集”(X_test),留著最後模型評估。然後再用交叉驗證,驗證正確率。(注意,這個資料集就有分佈規律,0-50為0類,50-100為1類,100-150為2類,所以用了隨機選取打亂了分佈。)

#split the train sets and test sets,
import knn
from sklearn.model_selection import train_test_split
X,X_test,y,y_test = train_test_split(data,target,test_size=0.2,random_state=1)
print X.shape,X_test.shape

#cross validation
folds = 4
k_choices = [1,3,5,7,9,13,15,20,25]

X_folds = []
y_folds = []

X_folds = np.vsplit(X,folds)
y_folds = np.hsplit(y,folds)

accuracy_of_k = {}
for k in k_choices:
    accuracy_of_k[k] = []
#split the train sets and validation sets
for i in range(folds):
    classify = knn.KNearestNeighbor()
    X_train =np.vstack(X_folds[:i] + X_folds[i+1:]) 
    X_val = X_folds[i]
    y_train = np.hstack(y_folds[:i] + y_folds[i+1:])
    y_val = y_folds[i]
    print X_train.shape,X_val.shape,y_train.shape,y_val.shape
    classify.train(X_train,y_train)
    for k in k_choices:
        y_val_pred = classify.predict(X_val,k = k)
        accuracy = np.mean(y_val_pred == y_val)
        accuracy_of_k[k].append(accuracy)

for k in sorted(k_choices):
    for accuracy in accuracy_of_k[k]:
        print 'k = %d,accuracy = %f' %(k,accuracy)
執行如下:

最後視覺化一下,選擇裡面平均值最好的K,

#show the plot
import matplotlib.pyplot as plt
#show the accuracy 
for k in k_choices:
    plt.scatter([k]*len(accuracy_of_k[k]), accuracy_of_k[k])
accuracies_mean = np.array([np.mean(v) for k,v in sorted(accuracy_of_k.items())])
accuracies_std = np.array([np.std(v) for k,v in sorted(accuracy_of_k.items())])
plt.errorbar(k_choices, accuracies_mean, yerr=accuracies_std)
plt.title('Cross-validation on k')
plt.xlabel('k')
plt.ylabel('Cross-validation accuracy')
plt.show()

最後再用測試集評估,這就得到了你的模型真正的效能!

#we chose the best one
best_k = 13
classify = knn.KNearestNeighbor()
classify.train(X_train,y_train)
y_test_pred = classify.predict(X_test,k=best_k)
num_correct = np.sum(y_test==y_test_pred)
accuracy_test = np.mean(y_test==y_test_pred)
print 'test accuracy is %d/%d = %f' %(num_correct,X_test.shape[0],accuracy_test)
執行得到:test accuracy is 24/30 = 0.800000

總之:交叉驗證可以幫助我們進行超引數的調優和模型選擇!