Machine Learning(14) - K Fold Cross Validation

Rachel發表於2019-06-18

引言

我們前面學了那麼多種 Machine Learning 的模型,那麼當我們拿到一個具體問題的時候,難免就會有疑惑,我究竟用哪個模型才是合適的呢?這節要講的 Cross Validation 就是用來解決這個問題的,它可以用來評估模型的表現。

Machine Learning(14) - K Fold Cross Validation

K Fold Cross Validation 的工作原理就是將一個資料集分成 K 份,遍歷 這 K 份資料,每次都是用其中的 1 份做測試,剩下的 K-1 份訓練資料,然後將每次求得的 score 取平均值。

正文

下面我們就以 ”手寫數字“ 的資料集為例,看下具體用法:

引入資料集

from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC
from sklearn.ensemble import RandomForestClassifier
import numpy as np
from sklearn.datasets import load_digits

digits = load_digits()

分別用 3 中模型處理模型,並測試其準確度

from sklearn.model_selection import train_test_split
// 將資料集分為訓練資料和測試資料
X_train, X_test, y_train, y_test = train_test_split(digits.data, digits.target, test_size=0.3)

lr = LogisticRegression()
lr.fit(X_train, y_train)
lr.score(X_test, y_test) // 輸出模型準確度 0.9592592592592593

svm = SVC()
svm.fit(X_train, y_train)
svm.score(X_test, y_test) // 輸出模型準確度 0.5074074074074074

rf = RandomForestClassifier()
rf.fit(X_train, y_train)
rf.score(X_test, y_test) // 輸出模型準確度 0.9481481481481482

這裡要說明的是,train_test_split() 函式對測試資料和訓練資料的分配是隨機的,也就是說沒執行一次,得到的分類都會不同。資料的不同,也會直接影響到模型的表現。

這裡大家可以嘗試多執行幾次 train_test_split() 函式,會發現 score 的值都會有所變化。

K fold

下面就引入我們上面所說的 K Fold 的概念:

from sklearn.model_selection import KFold
kf = KFold(n_splits = 3) // 會將處理的資料集分成 3 份
kf

// 輸出
KFold(n_splits=3, random_state=None, shuffle=False)

// 先用一個簡單的陣列做例子,來開下 KFold() 函式的效果
for train_index, test_index in kf.split([1, 2, 3, 4, 5, 6, 7, 8, 9]):
    print(train_index, test_index)

// 輸出
[3 4 5 6 7 8] [0 1 2]
[0 1 2 6 7 8] [3 4 5]
[0 1 2 3 4 5] [6 7 8]

以上輸出可以清楚地看出 KFold() 函式的作用,因為我們設定了引數 n_splits=3,所以它將資料平均地分成 3 份,每一份的資料組合都是不同的,並且保證每個數字都有出現在前後兩個陣列(訓練資料集和測試資料集)中的機會。

定義模型準確度的函式

下面我們把測試模型,測試模型的過程封裝成函式,方便後面使用:

def get_score(model, X_train, X_test, y_train, y_test):
    model.fit(X_train, y_train)
    return model.score(X_test, y_test)

用手寫數字集正式操練

這裡引用的是 StratifiedKFold,它的本質功能同前面的 KFold,區別是它在將資料分組的時候,會將資料打亂來分,準確性更高。

from sklearn.model_selection import StratifiedKFold
folds = StratifiedKFold(n_splits = 3)

// 為 3 個模型的預測值建立 3 個陣列
scores_l = []
scores_svm = []
scores_rf = []

// 把手寫數字的資料集分成 3 份,然後遍歷 3 次
for train_index, test_index in folds.split(digits.data, digits.target):
    // 取出每一次的訓練資料和測試資料
    X_train, X_test, y_train, y_test = digits.data[train_index], digits.data[test_index], digits.target[train_index], digits.target[test_index]
    // 把每一次得出模型準確度的值放進對應的陣列
    scores_l.append(get_score(LogisticRegression(), X_train, X_test, y_train, y_test))
    scores_svm.append(get_score(SVC(), X_train, X_test, y_train, y_test))
    scores_rf.append(get_score(RandomForestClassifier(n_estimators = 40), X_train, X_test, y_train, y_test))

// 輸出每種模型的準確度值的陣列    
scores_l
// 輸出
[0.8964941569282137, 0.9515859766277128, 0.9115191986644408]

scores_svm
// 輸出
[0.41068447412353926, 0.41569282136894825, 0.4273789649415693]

scores_rf
// 輸出
[0.9398998330550918, 0.9449081803005008, 0.9131886477462438]

用 cross_val_score 函式輕鬆實現

以上覆雜的操作過程,其實是在講 cross_val_score 的實現原理,實際上,我們用 cross_val_score 就可以輕鬆實現上面的過程:

from sklearn.model_selection import cross_val_score

cross_val_score(LogisticRegression(), digits.data, digists.target)

// 輸出
array([0.89534884, 0.94991653, 0.90939597])

cross_val_score(SVC(), digits.data, digists.target)
// 輸出
array([0.39368771, 0.41068447, 0.45973154])

cross_val_score(RandomForestClassifier(n_estimators = 40), digits.data, digists.target)

// 輸出
array([0.93189369, 0.94156928, 0.92281879])

使用 cross_val_score 不僅可以輕鬆測試每個模型的準確度,還可以對某個模型進行引數微調,比如上面對 RandomForestClassifier,就可以給它增加引數 n_estimators = 40 來調節它的準確度。

相關文章