1. 程式人生 > >機器學習-->sklearn.Cross-validation

機器學習-->sklearn.Cross-validation

本篇博文將主詳細講機器學習模型選擇中的交叉驗證,全文翻譯自sklearn.Cross-Validation。並且加上了我自己的一些見解。
學習預測函式的引數並在相同的資料上進行測試是一個方法上的錯誤:一個在訓練集上能取得很好的成績的模型,但是在測試集上效果卻很差,這種情況稱為過擬合。為了避免這種情況,通常(監督)機器學習實驗時將一部分可用資料儲存為測試集X_test,y_test。

train_test_split
scikit-learn可以將資料隨機分組為訓練集和測試集,使用train_test_split幫助函式快速計算。我們加iris資料集進行試驗。

>>> 
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,))

現在我們可以隨機的切分出40%的資料用於評價分類器效果好壞。

>>> 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
...

注意:這裡劃分是原始資料,不是劃分資料索引。
當評價不同超引數對應的學習器時,例如必須為SVM手動設定引數C時,仍然有可能在測試集上過度擬合,因為可以調整引數直到學習器效果最佳。這樣,關於測試集的知識可以“洩漏”到模型中,並且評估指標不再報告泛化效能。為了解決這個問題,資料集的另一部分可以被稱為所謂的“驗證集”:在訓練集上進行模型訓練,之後對驗證集進行評估調參,當實驗成功時,可以在測試集上進行最終評估。

然而,通過將可用資料分為三組,我們大大減少了可用於學習模型的樣本數,結果可能取決於一對(訓練,驗證)集合的特定隨機選擇。也即資料樣本沒有充分用來訓練模型。

解決這個問題的方法是一個稱為交叉驗證(簡稱CV)的過程。測試集仍是在最後用來評價模型好壞,但是在做CV時不再需要驗證集。在基本方法中,稱為k-fold CV,將訓練集分為k個較小的集合(其他方法如下所述,但通常遵循相同的原則)。對於k“folds”中的每一個,遵循以下過程:
• 隨機選取k-1折的資料進行模型訓練。
• 剩餘的一份資料用來驗證模型的好壞。

然後,迴圈中計算的值的平均值即是k-fold交叉驗證報告的效能指標。這種方法在計算上可能是昂貴的,但是不會浪費太多的資料(如固定任意測試集的情況),這是問題的主要優點,例如反向推理,其中樣本數量非常小。

計算交叉驗證的指標
使用交叉驗證的最簡單的方法是在學習器和資料集上呼叫cross_val_score函式。

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

預設情況下,每個CV迭代計算的分數是由分類器的score函式得出的。可以通過使用scoring引數來改變它:

>>> from sklearn import metrics
>>> scores = cross_val_score(
...     clf, iris.data, iris.target, cv=5, scoring='f1_macro')
>>> scores                                              
array([ 0.96...,  1.  ...,  0.96...,  0.96...,  1.        ])

當cv是整數時,預設情況下使用KFold 或者 StratifiedKFold 策略 進行劃分。
當然也可以利用其它策略

>>> from sklearn.model_selection import ShuffleSplit
>>> n_samples = iris.data.shape[0]
>##n_splits: 重新洗牌和分裂迭代次數
>>> cv = ShuffleSplit(n_splits=3, test_size=0.3, random_state=0)
>>> cross_val_score(clf, iris.data, iris.target, cv=cv)
...                                                     
array([ 0.97...,  0.97...,  1.        ])

通過交叉驗證獲取預測
函式cross_val_predict具有與cross_val_score類似的介面,但是對於輸入中的每個元素,返回當該元素在測試集中時獲得的預測。只有交叉驗證策略才能將所有元素精確地分配給測試集一次(否則引發異常)。
這種預測可以被運用到評價分類器:

>>> from sklearn.model_selection import cross_val_predict
>>> predicted = cross_val_predict(clf, iris.data, iris.target, cv=10)
>>> metrics.accuracy_score(iris.target, predicted) 
0.966...

注意,該計算的結果可能與使用cross_val_score獲得的結果略有不同,因為元素以不同的方式分組。

K-Fold
KFold將資料樣本k個小組,稱為分組。預測函式使用其中的k-1組資料進行學習,然後在剩下的一組資料上進行測試。每次選取不同的k-1組資料,直到選取完整個資料樣本。
注意這裡劃分的不是資料,而是資料對應的索引。

>>> import numpy as np
>>> from sklearn.model_selection import KFold
>>> X = ["a", "b", "c", "d"]
>>> kf = KFold(n_splits=2) 
>>> for train, test in kf.split(X): ##將X的索引分為兩份
...     print("%s %s" % (train, test))
##滿分,即分成的所有train能組成原始的索引,test同理。
[2 3] [0 1] #(train, test)
[0 1] [2 3] #(train, test)

每個摺疊由兩個陣列組成:第一個與訓練集相關,第二個與測試集相關。因此,可以使用numpy索引建立訓練/測試集:

>>> X = np.array([[0., 0.], [1., 1.], [-1., -1.], [2., 2.]])
>>> y = np.array([0, 1, 0, 1])
## 此時train=[0 1],test=[2 3]
>>> X_train, X_test, y_train, y_test = X[train], X[test], y[train], y[test]

Leave One Out(LOO)(留一法)
上面K-Fold是將n個數據樣本分為K份,這裡我們之間將其分為n份,我們每次取不同的n-1份用來訓練模型,用剩下的1份做測試集,這樣就會有n個不同訓練集合n個不同的測試集。
注意這裡劃分的不是資料,而是資料對應的索引

>>> from sklearn.model_selection import LeaveOneOut
>>> X = [1, 2, 3, 4]
>>> loo = LeaveOneOut()
>>> for train, test in loo.split(X):
...     print("%s %s" % (train, test))
[1 2 3] [0]
[0 2 3] [1]
[0 1 3] [2]
[0 1 2] [3]

選擇LOO贏應該注意一些已知的問題。與k折交叉驗證相比,一個構造n個樣本的n個模型,而不是k個模型,其中n>k。另外,每次n-1個樣本進行模型訓練。
就準確率來說,LOO可能會導致高方差,直觀的看,每次在n個樣本中選不同的n-1個樣本建立模型,一共訓練n個模型,因為每次選擇的訓練集都差不多,每次選擇的訓練集不具有獨立性,導致實際構建的模型都很相似,最後並沒有把方差降下來。
如果LOO與K-fold CV比較,LOO在N個樣本上建立N個模型而不是k個,更進一步,N個模型的每一個都是在N-1個樣本上訓練的,而不是(k-1)*n/k。兩種方法中,假定k不是很大,LOO比k-fold CV更耗時。

Leave P Out(LPO)(留P法)
LeavePOut與LeaveOneOut非常相似,因為它通過從完整資料樣本中拿取p個樣本建立測試集,剩餘n-p個樣本做訓練集。對於n個樣本,這產生{n \ choose p}訓練測試對。與LeaveOneOut和KFold不同,測試集樣本個數p> 1。當P>1時,測試集將會發生重疊,當P=1的時候,就變成了留一法
注意這裡劃分的不是資料,而是資料對應的索引

>>> from sklearn.model_selection import LeavePOut
>>> X = np.ones(4)
>>> lpo = LeavePOut(p=2)
>>> for train, test in lpo.split(X):
...     print("%s %s" % (train, test))
[2 3] [0 1]
[1 3] [0 2]
[1 2] [0 3]
[0 3] [1 2]
[0 2] [1 3]
[0 1] [2 3]

Random permutations cross-validation a.k.a Shuffle & Split
ShuffleSplit
ShuffleSplit迭代器產生指定數量的獨立的train/test資料集劃分,首先對樣本全體隨機打亂,然後再劃分出train/test對,可以使用隨機數種子random_state來控制數字序列發生器使得訊算結果可重現
ShuffleSplit是KFlod交叉驗證的比較好的替代,他允許更好的控制迭代次數和train/test的樣本比例
注意這裡劃分的不是資料,而是資料對應的索引

>>> from sklearn.model_selection import ShuffleSplit
>>> X = np.arange(5)
>>##n_splits: 重新洗牌和分裂迭代次數
>>> ss = ShuffleSplit(n_splits=3, test_size=0.25,
...     random_state=0)
>>> for train_index, test_index in ss.split(X):
...     print("%s %s" % (train_index, test_index))
[1 3 4] [2 0]
[1 4 3] [0 2]
[4 0 2] [1 3]

一些分類問題可能會在目標類別的分佈上表現出很大的不平衡:例如,負樣本數量可能是正樣本數量的數倍,在這種情況下,建議使用StratifiedKFold和StratifiedShuffleSplit中實施的分層取樣,以確保取樣出的資料樣本保持每個類原本所佔的百分比。
Stratified K-fold
StratifiedKFold是k-Fold的變體,它返回分層摺疊:每個集合大致保持了與原始完整集合中每個類的百分比。
注意這裡劃分的不是資料,而是資料對應的索引

>>> from sklearn.model_selection import StratifiedKFold
>>> X = np.ones(10)
>>> y = [0, 0, 0, 0, 1, 1, 1, 1, 1, 1]
>>> skf = StratifiedKFold(n_splits=3)
>>> for train, test in skf.split(X, y):
...     print("%s %s" % (train, test))
[2 3 6 7 8 9] [0 1 4 5]
[0 1 3 4 5 8 9] [2 6 7]
[0 1 2 4 5 6 7] [3 8 9]

StratifiedShuffleSplit和ShuffleSplit的一個變體,返回分層劃分,也就是在建立劃分的時候要保證每一個劃分中類的樣本比例與整體資料集中的原始比例保持一致

Cross-Validation iteration for grouped data
如果潛在的生成過程產生相互依賴樣本集,那麼獨立同分布的假設就不復存在。

這樣的資料分組,其域特定的。舉個例子,一個關於醫學的資料集,這個資料集是從多個患者收集到的。從一個患者取出多個樣本。而這些資料很可能取決於個別群體。在我們的示例中,每個樣本的患者ID是其組識別符號。

在這種情況下,我們想知道一個針對特定組的訓練模型,是否在其他的組上有好效果。
我的理解:資料樣本除了對應的標籤類別以外,還有組group的分別,而相同的組之間特徵依賴性又很高,如果不考慮組這個因素,直接拿進模型訓練,那麼這個模型的泛化能力肯定很弱,即是可能會有過擬合情況。GroupKFold可以檢測到這種過度擬合情況。
其實就是按照groups(n組)對資料樣本分割成k(k<=n)份,然後每次選擇不同的k-1份做訓練集,剩餘的一份做測試集。
注意這裡劃分的不是資料,而是資料對應的索引

>>> from sklearn.model_selection import GroupKFold
>>> X = [0.1, 0.2, 2.2, 2.4, 2.3, 4.55, 5.8, 8.8, 9, 10]
>>> y = ["a", "b", "b", "b", "c", "c", "c", "d", "d", "d"]
>>> groups = [1, 1, 1, 2, 2, 2, 3, 3, 3, 3]
##n_splits=3是按groups進行分割,表示按groups將樣本分為3份,每一份都是原本的一組
>>> gkf = GroupKFold(n_splits=3)
>>> for train, test in gkf.split(X, y, groups=groups):
...     print("%s %s" % (train, test))
[0 1 2 3 4 5] [6 7 8 9]
[0 1 2 6 7 8 9] [3 4 5]
[3 4 5 6 7 8 9] [0 1 2]
若:
>>> gkf = GroupKFold(n_splits=2)##表示按groups將資料樣本分為2份
>>> for train, test in gkf.split(X, y, groups=groups):
...     print("%s %s" % (train, test))
[0 1 2 3 4 5] [6 7 8 9]
[6 7 8 9] [0 1 2 3 4 5]

由以上結果可以看出,同一組的資料樣本不可能同時出現在訓練集和測試集。

Leave One Group Out
其實就是按照groups(n組)對資料樣本分割成n份,然後每次選擇不同的n-1份做訓練集,剩餘的一份做測試集。
注意這裡劃分的不是資料,而是資料對應的索引

>>> from sklearn.model_selection import LeaveOneGroupOut
>>> X = [1, 5, 10, 50, 60, 70, 80]
>>> y = [0, 1, 1, 2, 2, 2, 2]
>>> groups = [1, 1, 2, 2, 3, 3, 3]
>>> logo = LeaveOneGroupOut()
>>> for train, test in logo.split(X, y, groups=groups):
...     print("%s %s" % (train, test))
[2 3 4 5 6] [0 1]
[0 1 4 5 6] [2 3]
[0 1 2 3] [4 5 6]

另一個常見的應用是使用時間資訊:例如,組可以是取樣的年份,從而允許基於時間分割的交叉驗證。

Leave P Groups Out
類似於Leave One Group Out,只不過這裡不是隻選一組資料做測試集,而是選p組。(p>1)
注意這裡劃分的不是資料,而是資料對應的索引

>>> from sklearn.model_selection import LeavePGroupsOut
>>> X = np.arange(6)
>>> y = [1, 1, 1, 2, 2, 2]
>>> groups = [1, 1, 2, 2, 3, 3]
>>> lpgo = LeavePGroupsOut(n_groups=2)
>>> for train, test in lpgo.split(X, y, groups=groups):
...     print("%s %s" % (train, test))
[4 5] [0 1 2 3]
[2 3] [0 1 4 5]
[0 1] [2 3 4 5]

Group Shuffle Split
Group Shuffle Split 結合了ShffleSplit和LeavePGroupsOut。
注意這裡劃分的不是資料,而是資料對應的索引

>>> from sklearn.model_selection import GroupShuffleSplit
>>> X = [0.1, 0.2, 2.2, 2.4, 2.3, 4.55, 5.8, 0.001]
>>> y = ["a", "b", "b", "b", "c", "c", "c", "a"]
>>> groups = [1, 1, 2, 2, 3, 3, 4, 4]
## n_splits=4:表示按組將資料樣本分組,test_size就是LeavePGroupsOut中的p
>>> gss = GroupShuffleSplit(n_splits=4, test_size=0.5, random_state=0)
>>> for train, test in gss.split(X, y, groups=groups):
...     print("%s %s" % (train, test))
[0 1 2 3] [4 5 6 7]
[2 3 6 7] [0 1 4 5]
[2 3 4 5] [0 1 6 7]
[4 5 6 7] [0 1 2 3]

相關推薦

機器學習-->sklearn.Cross-validation

本篇博文將主詳細講機器學習模型選擇中的交叉驗證,全文翻譯自sklearn.Cross-Validation。並且加上了我自己的一些見解。 學習預測函式的引數並在相同的資料上進行測試是一個方法上的錯誤:一個在訓練集上能取得很好的成績的模型,但是在測試集上效果卻很

python機器學習-sklearn挖掘乳腺癌細胞(三)

質量 mat spl tcl pytho 不同 區別 工具 state python機器學習-sklearn挖掘乳腺癌細胞( 博主親自錄制) 網易雲觀看地址 https://study.163.com/course/introduction.htm?courseId=10

python機器學習-sklearn挖掘乳腺癌細胞(五)

糾正 plot 不錯 方法 eid right ref nump cores python機器學習-sklearn挖掘乳腺癌細胞( 博主親自錄制) 網易雲觀看地址 https://study.163.com/course/introduction.htm?courseId

機器學習sklearn中的train_test_split()函式

使用train_test_split函式可以將原始資料集按照一定比例劃分訓練集和測試集對模型進行訓練 一、舉例 import numpy as np #科學計算庫 from sklearn.model_selection import train_test_split #train_test_s

python 機器學習 sklearn 廣義線性模型

廣義的線性模型是最最常用和我個人認為最重要的 最小二乘 class sklearn.linear_model.LinearRegression(fit_intercept=True, normalize=False, copy_X=

機器學習基石 Lecture15: Validation

機器學習基石 Lecture15: Validation Model Selection Problem Validation Leave-One-Out Cross Validation V-Fold Cross Validation

機器學習+sklearn框架】(一) 線性模型之Linear Regression

前言 一、原理    1.演算法含義    2.演算法特點 二、實現   1.sklearn中的線性迴歸   2.用Python自己實現演算法 三、思考(面試常問) 參考 前言        線性迴歸(Linear Regression)基本上可以說是機器

機器學習 sklearn】手寫數字識別 SVM

執行結果: "D:\Program Files\Python27\python.exe" D:/PycharmProjects/sklearn/SVM.py (1797L, 64L) [[ 0. 0. 5. ..., 0. 0. 0.]

機器學習 sklearn】XGBclassifier 超引數尋優

程式碼片段 # encoding: utf-8 import sys reload(sys) sys.setdefaultencoding('utf-8') import pandas as pd train = pd.read_csv('train.csv

機器學習sklearn的快速使用--周振洋

ML神器:sklearn的快速使用 傳統的機器學習任務從開始到建模的一般流程是:獲取資料 -> 資料預處理 -> 訓練建模 -> 模型評估 -> 預測,分類。本文我們將依據傳統機器學習的流程,看看在每一步流程中都有哪些常用的函式以及它們的用法是怎麼樣的。希望

機器學習——sklearn中的交叉驗證

[0.95999999999999996, 0.95333333333333337, 0.96666666666666656, 0.96666666666666656, 0.96666666666666679, 0.96666666666666679, 0.96666666666666679, 0.9666

8.機器學習sklearn---多項式迴歸(房價與房屋尺寸關係的非線性擬合)

1.基本概念多項式迴歸(Polynomial Regression)是研究一個因變數與一個或多個自變數間多項式的迴歸分析方法。如果自變數只有一個 時,稱為一元多項式迴歸;如果自變數有多個時,稱為多元多項式迴歸。         1.在一元迴歸分析中,如果依變數y與自變數x的關

機器學習sklearn庫的使用--部署環境(python2.7 windows7 64bit)

最近在學習機器學習的內容,難免地,要用到Scikit-learn(sklearn,下同)這一機器學習包。為了使用sklearn庫,我們需要安裝python2.7,pip install工具,numpy+mkl、scipy、pandas、sklearn等開源包。其

機器學習sklearn iris資料集官方demo

sklearn是谷歌開發的一個機器學習框架,也是很多小夥伴在學習機器學習的時候最早接觸的東西。sklearn中自帶了四個小資料集,其中一個很常用的就是iris鳶尾花資料集,很多學習演算法都可以在這個例子上進行實驗。 所以,本文我把sklearn官方關於這個資料集在PCA演算

機器學習 sklearn】邏輯斯蒂迴歸模型--Logistics regression

執行結果: "D:\Program Files\Python27\python.exe" D:/PycharmProjects/sklearn/Logistics_regression.py Logistics regression [[99 1] [

機器學習sklearn之菜鳥入門一

from sklearn.datasets import load_iris from sklearn.cross_validation import train_test_split from sklearn.neighbors import KNeighborsClassifier from sklear

9.機器學習sklearn-----嶺迴歸及其應用例項

1.基本概念對於一般地線性迴歸問題,引數的求解採用的是最小二乘法,其目標函式如下:引數w的求解,也可以使用如下矩陣方法進行:       對於矩陣X,若某些列線性相關性較大(即訓練樣本中某些屬性線性相關),就會導致,就會導致XTX的值接近0,在計算(XTX)-1時就會出現不穩

機器學習-Sklearn

and learn ams 而且 dev option ring app 模型 Scikit learn 也簡稱 sklearn, 是機器學習領域當中最知名的 python 模塊之一. Sklearn 包含了很多種機器學習的方式: Classification

7.機器學習sklearn-------線性迴歸(房價與房屋尺寸關係的線性擬合)

1.基本概念線性迴歸(Linear Regression)是利用數理統計中迴歸分析, 來確定兩種或兩種以上變數間相互依賴的定量關係的一種統計分 析方法。 線性迴歸利用稱為線性迴歸方程的最小平方函式對一個或多個自變數和因變數之間關係進行建模。這種函式是一個或多個稱為回 歸係數的

機器學習sklearn多元線性迴歸

from __future__ import print_function from sklearn import datasets from sklearn.linear_model import