摘要: 本文講述瞭如何用Python對訓練集測試集進行分割與交叉驗證。
在上一篇關於Python中的線性迴歸的文章以後,我想再寫一篇關於訓練測試分割和交叉驗證的文章。在數據科學和數據分析領域中,這兩個概念常常被用做防止或最小化過分擬合的工具。我會解釋當使用統計模型時,一般將模型擬合在訓練集上,以便對未被訓練的數據進行預測。html
在統計學和機器學習領域中,咱們一般把數據分紅兩個子集:訓練數據和測試數據,而且把模型擬合到訓練數據上,以便對測試數據進行預測。當作到這一點時,可能會發生兩種狀況:模型的過分擬合或欠擬合。咱們不但願出現這兩種狀況,由於這會影響模型的可預測性。咱們有可能會使用具備較低準確性或不經常使用的模型(這意味着你不能泛化對其它數據的預測)。python
什麼是模型的過分擬合(Overfitting)和欠擬合(Underfitting)?web
過分擬合意味着模型訓練得「太好」了,而且與訓練數據集過於接近了。這一般發生在模型過於複雜的狀況下,模型在訓練數據上很是的準確,但對於未訓練數據或者新數據可能會很不許確。由於這種模型不是泛化的,意味着你能夠泛化結果,而且不能對其它數據進行任何推斷,這大概就是你要作的。基本上,當發生這種狀況時,模型學習或描述訓練數據中的「噪聲」,而不是數據中變量之間的實際關係。這種噪聲顯然不是任何新數據集的一部分,不能應用於它。dom
與過分擬合相反,當模型欠擬合的時候,它意味着模型不適合訓練數據,所以會錯過數據中的趨勢特色。這也意味着該模型不能被泛化到新的數據上。你可能猜到了,這一般是模型很是簡單的結果。例如,當咱們將線性模型(如線性迴歸)擬合到非線性的數據時,也會發生這種狀況。不言而喻,該模型對訓練數據的預測能力差,而且還不能推廣到其它的數據上。機器學習
值得注意的是,欠擬合不像過分擬合那樣廣泛。然而,咱們但願避免數據分析中的這兩個問題。你可能會說,咱們正在試圖找到模型的欠擬合與過分擬合的中間點。像你所看到的,訓練測試分割和交叉驗證有助於避免過分擬合超過欠擬合。函數
正如我以前所說的,咱們使用的數據一般被分紅訓練數據和測試數據。訓練集包含已知的輸出,而且模型在該數據上學習,以便之後將其泛化到其它數據上。咱們有測試數據集(或子集),爲了測試模型在這個子集上的預測。工具
咱們將使用Scikit-Learn library,特別是其中的訓練測試分割方法。咱們將從導入庫開始:學習
快速地看一下導入的庫:測試
好了,一切都準備就緒,讓咱們輸入糖尿病數據集,將其轉換成數據幀並定義列的名稱:大數據
如今咱們可使用train_test_split函數來進行分割。函數內的test_size=0.2代表了要測試的數據的百分比,一般是80/20或70/30左右。
# create training and testing vars X_train, X_test, y_train, y_test = train_test_split(df, y, test_size=0.2) print X_train.shape, y_train.shape print X_test.shape, y_test.shape (353, 10) (353,) (89, 10) (89,)
如今咱們將在訓練數據上擬合模型:
# fit a model lm = linear_model.LinearRegression() model = lm.fit(X_train, y_train) predictions = lm.predict(X_test)
正如所看到的那樣,咱們在訓練數據上擬合模型並嘗試預測測試數據。讓咱們看一看都預測了什麼:
predictions[0:5] array([ 205.68012533, 64.58785513, 175.12880278, 169.95993301, 128.92035866])
注:由於我在預測以後使用了[0:5],它只顯示了前五個預測值。去掉[0:5]的限制就會使它輸出咱們模型建立的全部預測值。
讓咱們來繪製模型:
## The line / model plt.scatter(y_test, predictions) plt.xlabel(「True Values」) plt.ylabel(「Predictions」)
打印準確度得分:
print 「Score:」, model.score(X_test, y_test) Score: 0.485829586737
總結:將數據分割成訓練集和測試集,將回歸模型擬合到訓練數據,基於該數據作出預測,並在測試數據上測試預測結果。可是訓練和測試的分離確實有其危險性,若是咱們所作的分割不是隨機的呢?若是咱們數據的一個子集只包含來自某個州的人,或者具備必定收入水平但不包含其它收入水平的員工,或者只有婦女,或者只有某個年齡段的人,那該怎麼辦呢?這將致使過分擬合,即便咱們試圖避免,這就是交叉驗證要派上用場了。
在前一段中,我提到了訓練測試分割方法中的注意事項。爲了不這種狀況,咱們能夠執行交叉驗證。它很是相似於訓練測試分割,可是被應用於更多的子集。意思是,咱們將數據分割成k個子集,並訓練第k-1個子集。咱們要作的是,爲測試保留最後一個子集。
有一組交叉驗證方法,我來介紹其中的兩個:第一個是K-Folds Cross Validation,第二個是Leave One Out Cross Validation (LOOCV)。
在K-Folds交叉驗證中,咱們將數據分割成k個不一樣的子集。咱們使用第k-1個子集來訓練數據,並留下最後一個子集做爲測試數據。而後,咱們對每一個子集模型計算平均值,接下來結束模型。以後,咱們對測試集進行測試。
這裏有一個在Sklearn documentation上很是簡單的K-Folds例子:
fromsklearn.model_selection import KFold # import KFold X = np.array([[1, 2], [3, 4], [1, 2], [3, 4]]) # create an array y = np.array([1, 2, 3, 4]) # Create another array kf = KFold(n_splits=2) # Define the split - into 2 folds kf.get_n_splits(X) # returns the number of splitting iterations in the cross-validator print(kf) KFold(n_splits=2, random_state=None, shuffle=False)
讓咱們看看結果:
fortrain_index, test_index in kf.split(X): print(「TRAIN:」, train_index, 「TEST:」, test_index) X_train, X_test = X[train_index], X[test_index] y_train, y_test = y[train_index], y[test_index] ('TRAIN:', array([2, 3]), 'TEST:', array([0, 1])) ('TRAIN:', array([0, 1]), 'TEST:', array([2, 3]))
正如看到的,函數將原始數據拆分紅不一樣的數據子集。這是個很是簡單的例子,但我認爲它把概念解釋的至關好。
這是另外一種交叉驗證的方法,棄一法交叉驗證。能夠在Sklearn website上查看。在這種交叉驗證中,子集的數量等於咱們在數據集中觀察到的數量。而後,咱們計算全部子集的平均數,並利用平均值創建模型。而後,對最後一個子集測試模型。由於咱們會獲得大量的訓練集(等於樣本的數量),所以這種方法的計算成本也至關高,應該在小數據集上使用。若是數據集很大,最好使用其它的方法,好比kfold。
讓咱們看看Sklearn上的另外一個例子:
fromsklearn.model_selectionimportLeaveOneOut X = np.array([[1, 2], [3, 4]]) y = np.array([1, 2]) loo = LeaveOneOut() loo.get_n_splits(X) fortrain_index, test_indexinloo.split(X): print("TRAIN:", train_index, "TEST:", test_index) X_train, X_test = X[train_index], X[test_index] y_train, y_test = y[train_index], y[test_index] print(X_train, X_test, y_train, y_test)
如下是輸出:
('TRAIN:', array([1]), 'TEST:', array([0])) (array([[3, 4]]), array([[1, 2]]), array([2]), array([1])) ('TRAIN:', array([0]), 'TEST:', array([1])) (array([[1, 2]]), array([[3, 4]]), array([1]), array([2]))
那麼,咱們應該使用什麼方法呢?使用多少子集呢?擁有的子集越多,咱們將會因爲誤差而減小偏差,但會因爲方差而增長偏差;計算成本也會上升,顯然,擁有的子集越多,計算所需的時間就越長,也將須要更多的內存。若是利用數量較少的子集,咱們減小了因爲方差而產生的偏差,可是因爲誤差引發的偏差會更大。它的計算成本也更低。所以,在大數據集中,一般建議k=3。在更小的數據集中,正如我以前提到的,最好使用棄一法交叉驗證。
讓咱們看看之前用過的一個例子,此次使用的是交叉驗證。我將使用cross_val_predict函數來給每一個在測試切片中的數據點返回預測值。
# Necessary imports: from sklearn.cross_validation import cross_val_score, cross_val_predict from sklearn import metrics
以前,我給糖尿病數據集創建了訓練測試分割,並擬合了一個模型。讓咱們看看在交叉驗證以後的得分是多少:
# Perform 6-fold cross validation scores = cross_val_score(model, df, y, cv=6) print 「Cross-validated scores:」, scores Cross-validated scores: [ 0.4554861 0.46138572 0.40094084 0.55220736 0.43942775 0.56923406]
正如你所看到的,最後一個子集將原始模型的得分從0.485提升到0.569。這並非一個驚人的結果,但咱們獲得了想要的。
如今,在進行交叉驗證以後,讓咱們繪製新的預測圖:
# Make cross validated predictions predictions = cross_val_predict(model, df, y, cv=6) plt.scatter(y, predictions)
你能夠看到這和原來的圖有很大的不一樣,是原來圖的點數的六倍,由於我用的cv=6。
最後,讓咱們檢查模型的R²得分(R²是一個「表示與自變量分離的可預測的因變量中方差的比例的數量」)。能夠看一下咱們的模型有多準確:
accuracy = metrics.r2_score(y, predictions) print 「Cross-Predicted Accuracy:」, accuracy Cross-Predicted Accuracy: 0.490806583864
本文爲雲棲社區原創內容,未經容許不得轉載。