引言
我們前面學了那麼多種 Machine Learning 的模型,那麼當我們拿到一個具體問題的時候,難免就會有疑惑,我究竟用哪個模型才是合適的呢?這節要講的 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
來調節它的準確度。