1.過擬合與樂觀模型
有監督學習的基本目標是准確預測,當對模型進行性能評估時,需要確定模型對新數據的性能如何。即需要一個指標來確定預測的泛化能力如何。對於回歸問題來說,標准評價指標是均方誤差(Mean Squared Error)。它是目標變量真實值和預測值之差的平方和的均值。參看下圖(學習自 Real-World Machine Learning)的例子:
左圖中隨着帶寬參數的增加,模型趨於欠擬合,而在最左邊的圖中明顯是過擬合,而此時的模型MSE(均方誤差)最小,但是泛化誤差卻可能是最大的。所以訓練集誤差與機器學習模型的泛化誤差之間發生了分歧。這可以在上圖右圖中看到。看到訓練集(藍色曲線)誤差最小的時候對應最小的帶寬參數,這時你會誤認為此時的模型最優,但是這時的模型發生了嚴重的過擬合使得在新數據上的誤差最大!所以在模型擬合和評價中都使用訓練數據會使你對模型又過於樂觀的估計。總結:當帶寬參數最小的時候 ,此時訓練集誤差最小,過擬合最嚴重,泛化能力最弱。隨着帶寬參數的增加,模型的復雜度在降低,在帶寬參數達到0.12的時候,此時模型在新數據性能上最優。而隨着帶寬參數繼續增加,模型又陷入了欠擬合。 根據藍色曲線,我們會錯誤的選擇0.01的帶寬參數,因為訓練集上的MSE只有0.08,但是新數據上的MSE高達0.50!所以我們需要有一種評價指標使得我們可以挑選出合適的帶寬參數約為0.12,此時新數據上的MSE才最小為0.27。所以需要換一種模型評價方法:交叉驗證。
交叉驗證
上面看到訓練集誤差並不能代表模型在新數據上的誤差。為了估計模型在新數據上的錯誤率,需要利用交叉驗證(CV),嚴格使用訓練集評估新數據的准確性。交叉驗證常用的兩種方法:保持法(holdout method)和K-折交叉驗證(k-fold cross-validation)。
1)保持法
最簡單的方法是用獨立的訓練集合測試集。集將訓練集中抽取一部分用作測試集。通常會取20%-40%的數據作為測試集。還是上面的例子,看下保持法計算的評估誤差和新數據誤差的關系:明顯看出保持法計算的評估誤差接近模型的新數據誤差。它們比訓練集的估計誤差更接近,特別是在帶寬參數值較小的時候。但是問題也很明顯,保持法的噪聲較大,根據下圖中大約帶寬參數為0.15時,保持法得到的MSE標准為0.15,實際新數據的MSE為0.27.所以保持法使得我們會選擇0.14的帶寬參數,這與0.12的最優參數很接近了!比起訓練集MSE最小化推薦給我們的參數0.01好太多。可以通過重復的訓練-測試集划分,並對結果取均值來消除噪聲,但是在多次循環中,每個數據點會被多次分配到測試集中,使結果有偏差。更好的方法是K-折交叉驗證。
采用保持法得到的評估誤差 采用K-折交叉驗證得到的評估誤差
2)K-折交叉驗證
和保持法一樣,k-折交叉驗證依賴於訓練數據隔離,但不同的是,K-折交叉驗證隨機的把數據分成k個互不相交的子集,稱為包(fold)。k可以取5、10、20...。對於每個包只作為驗證集。所以不會有相同的數據點進入測試集中。采用10折交叉驗證的結果如上圖,K-折交叉驗證估計誤差與新數據上的誤差非常接近。
1)保持法
>>> import numpy as np
>>> from sklearn.model_selection import train_test_split >>> from sklearn import datasets >>> from sklearn import svm >>> iris = datasets.load_iris() >>> iris.data.shape, iris.target.shape ((150, 4), (150,))
取iris數據集的訓練樣本,將其按照0.4的比例划分為訓練集和測試集。采用svm進行訓練,驗證其在測試機上的表現。為了解決模型可能出現的過擬合問題,可以將所有樣本划分為訓練集、交叉驗證集和測試集。即用訓練樣本訓練,利用交叉驗證集來評估,當在交叉驗證集上表現較好時再用測試集進行最終驗證。但這樣就導致最初的樣本被分為三個子集,在訓練的時候就沒有足夠多的樣本數量(本應該用所有樣本來訓練),結果很可能會受到某一特定驗證集和測試集的影響。一種方案就是測試集仍然應該被分出來,但是交叉驗證集不需單獨划分,就是利用K-折交叉驗證即可。這樣就不會損失太多訓練樣本,雖然計算代價較大。
>>> X_train, X_test, y_train, y_test = train_test_split(iris.data, iris.target, test_size=0.4, random_state=0) >>> X_train.shape, y_train.shape ((90, 4), (90,)) >>> X_test.shape, y_test.shape ((60, 4), (60,)) >>> clf = svm.SVC(kernel='linear', C=1).fit(X_train, y_train) >>> clf.score(X_test, y_test) 0.96...
2)Computing cross-validated metrics
利用sklearn中的cross_va_score函數作為數據集的評估。以下是利用5折交叉驗證評估svm在iris數據集上的打分表現。
>>> from sklearn.model_selection import cross_val_score
>>> clf = svm.SVC(kernel='linear', C=1) >>> scores = cross_val_score(clf, iris.data, iris.target, cv=5) >>> scores array([ 0.96..., 1. ..., 0.96..., 0.96..., 1. ])
得分平均值和95%的自信度得分范圍:
>>> print("Accuracy: %0.2f (+/- %0.2f)" % (scores.mean(), scores.std() * 2))
Accuracy: 0.98 (+/- 0.03)
3.交叉驗證注意事項
交叉驗證可以幫我們選擇最佳模型,但實際應用中需注意幾個問題:
1)交叉驗證法假定訓練數據是有代表性的。否則解決方法:保證訓練數據中的所有潛在偏見都被找到並最小化。
2)K折交叉驗證中包的數量越多,估計誤差越好,但也更耗時間。解決方法:可能的話至少使用10個包,對於訓練和預測較快的模型,可以使用單一保留(leave-one-out)交叉驗證(k=數據實例個數)。