主頁 >  其他 > 深入理解交叉驗證與網格搜索——sklearn實作

深入理解交叉驗證與網格搜索——sklearn實作

2022-02-16 07:59:17 其他

交叉驗證(Cross Validation)和網格搜索(Grid Search)常結合在一起并用來篩選模型的最優引數,本文將從零開始一步步講解交叉驗證和網格搜索的由來,并基于sklearn實作它們,

目錄

  • 一、交叉驗證法
    • 1.1 交叉驗證法的由來
    • 1.2 交叉驗證法的定義
    • 1.3 sklearn.model_selection.train_test_split()
    • 1.4 sklearn.metrics.accuracy_score()
      • 1.4.1 clf.score 與 accuracy_score 的區別
    • 1.5 sklearn.model_selection.cross_val_score()
  • 二、網格搜索法
    • 2.1 網格搜索法的由來
    • 2.2 使用 for 回圈實作網格搜索
    • 2.3 sklearn.model_selection.GridSearchCV()
      • 2.3.1 引數
      • 2.3.2 方法
      • 2.3.3 屬性
  • 三、專案實戰——鳶尾花分類
    • 3.1 鳶尾花資料集介紹
    • 3.2 sklearn.datasets.load_iris()
    • 3.3 代碼實作
  • References

一、交叉驗證法

1.1 交叉驗證法的由來

在機器學習中,我們通常是將已有的資料集(Data Set)一分為二(不一定等分),一部分是訓練集(Training Set),一部分是測驗集(Test Set),通常,我們會在訓練集上訓練模型(Model),然后在測驗集上評估模型的性能(Performance),評估性能需要用到性能度量(Performance Measure),即衡量模型好壞的指標,本文將使用準確率(accuracy)作為性能度量,

以軟間隔SVM為例,其中的引數 C C C 需要事先給定,我們將這種需要事先給定的引數稱為超引數(Hyperparameter),如果選用高斯核、多項式核、Sigmoid核,則其中的引數 γ , r , d \gamma, r, d γ,r,d 也是超引數,我們先只考慮線性核,也就是只有一個超引數的情形,

首先將資料集分為訓練集和測驗集,這個時候訓練集和測驗集已經固定了:

對于每個固定的 C C C,我們在訓練集上訓練都會得到一個軟間隔SVM模型,然后在測驗集上評估該模型的分類準確率,如果準確率高,我們就說模型是好的,反之則較差,我們自然是想找到使得分類準確率最高的那個 C C C,因為它對應的模型是最好的,尋找 “最好” 的 C C C 的這一程序稱為調參(Parameter Tuning),即不斷調整引數使得訓練出來的模型最優,“最好” 的 C C C 也稱為最優引數(Best Parameter),

為了敘述方便起見,我們接下來將模型在測驗集上的分類準確率稱為得分(Score),此外,因為當確定引數 C C C 后,模型也就隨之確定了,即引數和模型之間是一個一一對應的關系,所以我們后續也會使用 “引數的得分” 這種說法,

假設我們已經找到了最優引數: C b e s t C_{best} Cbest?,它所對應的模型的得分最高,現在,我們想測驗這個最優模型的泛化能力,可已經沒有資料供我們測驗了,如果還在測驗集上去測驗這個最優模型的性能,那無疑是重復勞動,因為我們在調參的程序中就已經在測驗集上測驗了每個模型的性能,另一方面,因為我們的 C C C 是根據模型在測驗集上的得分來進行選取的,也就是說,測驗集中的 “知識” 已經滲入到了我們的最優模型當中,這就會導致過擬合,從而降低了模型的泛化能力,

解決該問題的一個方法就是,將原先的訓練集一分為二,一部分用作訓練集,一部分用作驗證集(Validation Set),驗證集用來選擇最優引數,得到最優引數后再在原先的訓練集上重新訓練,得到的模型在測驗集上評估最終性能(Final Evaluation),

因為我們在得到最優引數之前都是在驗證集上對每個模型(引數)進行打分的,得分最高的成為最優引數,換句話說,最優引數與驗證集有關,而驗證集是從原先的訓練集劃分得來,這種劃分具有一定的偶然性,這就可能導致我們的最優引數是在眾多引數之中 “僥幸” 取勝,即最優引數更適合這個驗證集,如果換成另外一個驗證集,它可能就不是最優的了,

舉個例子,設原先的訓練集為 T T T,考慮兩種劃分方式: T = ( T \ V 1 ) ? ? ? V 1 T=(T\backslash V_1)\,\bigcup\, V_1 T=(T\V1?)?V1? T = ( T \ V 2 ) ? ? ? V 2 T=(T\backslash V_2)\,\bigcup\, V_2 T=(T\V2?)?V2?,其中 V 1 , V 2 V_1, V_2 V1?,V2?不同的驗證集, T \ V 1 , T \ V 2 T\backslash V_1, T\backslash V_2 T\V1?,T\V2? 是訓練集,則可能會出現:

  • 驗證集為 V 1 V_1 V1? 時,最優引數為 C = 1 C=1 C=1,最差引數為 C = 1000 C=1000 C=1000
  • 驗證集為 V 2 V_2 V2? 時,最優引數為 C = 1000 C=1000 C=1000,最差引數為 C = 1 C=1 C=1

那么如何減少這種偶然性呢?直觀來看,應該取多個驗證集 V 1 , V 2 , ? ? , V m V_1, V_2,\cdots, V_m V1?,V2?,?,Vm?,引數在每個驗證集 V i V_i Vi? 上都會有一個得分 S i S_i Si?,這些得分的平均 S  ̄ = ( S 1 + ? + S m ) / m \overline{S}=(S_1+\cdots+S_m)/m S=(S1?+?+Sm?)/m 就作為這個引數的得分,

注意到驗證集是從原先的訓練集劃分得來,即 V i ? T , ?? i = 1 , ? ? , m V_i\subset T,\; i=1,\cdots,m Vi??T,i=1,?,m,為了進一步減少偶然性,很自然的一個想法就是把原先的訓練集全部用上并要求驗證集兩兩互斥且大小相等,即:

T = V 1 ? ∪ ? V 2 ? ∪ ? ∪ ? V m , ∣ V 1 ∣ = ∣ V 2 ∣ = ? = ∣ V m ∣ , V i ? ∩ ? V j = ? ( i ≠ j ) T=V_1\, \cup\, V_2\, \cup\cdots\cup\, V_m,\quad |V_1|=|V_2|=\cdots=|V_m|,\quad V_i\,\cap\, V_j=\varnothing(i\neq j) T=V1?V2??Vm?,V1?=V2?=?=Vm?,Vi?Vj?=?(i?=j)

這樣我們就得到了 m m m 組訓練集 / / /驗證集,對于每一個引數,它的得分就是在這 m m m 個驗證集上得分的均值

T = ( T \ V 1 ) ? ∪ ? V 1 ? S 1 T = ( T \ V 2 ) ? ∪ ? V 2 ? S 2 ?????????????????????????????????????????????????????????????????????????????????? ? ? T = ( T \ V m ) ? ∪ ? V m ? S m ? S  ̄ = S 1 + ? + S m m \begin{aligned} T=(T\backslash V_1)\,\cup\, V_1 \quad\Rightarrow\quad &S_1 \\ T=(T\backslash V_2)\,\cup\, V_2 \quad\Rightarrow\quad &S_2\\ &\!\!\!\!\!\!\!\!\!\!\!\!\!\!\!\!\!\!\!\!\!\!\!\!\!\!\!\!\!\!\!\!\!\!\!\!\!\!\!\!\!\vdots\quad\quad\quad\quad\quad\quad\quad\vdots \\ T=(T\backslash V_m)\,\cup\, V_m \quad\Rightarrow\quad &S_m \\ \end{aligned} \quad\Longrightarrow\quad \overline{S}=\frac{S_1+\cdots +S_m}{m} T=(T\V1?)V1??T=(T\V2?)V2??T=(T\Vm?)Vm???S1?S2???Sm???S=mS1?+?+Sm??

S  ̄ \overline{S} S 最高的引數成為我們的最優引數,下面的圖更形象的展示了這一程序:

得到最優引數后,我們再在原先的訓練集上重新訓練,完整的流程圖如下:

很多時候,我們的 T T T 做不到 m m m 等分,那只能退而求其次,要求

∣ V 1 ∣ ≈ ∣ V 2 ∣ ≈ ? ≈ ∣ V m ∣ |V_1|\approx|V_2|\approx\cdots\approx|V_m| V1?V2??Vm?

這便是交叉驗證法,

1.2 交叉驗證法的定義

( 交 叉 驗 證 法 ) ?? \textcolor{purple}{(交叉驗證法)}\; () 將資料集 D D D(原先的訓練集)劃分為 k k k 個大小相似互斥子集,每個子集 D i D_i Di? 盡可能保持資料分布的一致性,即從 D D D 中通過分層采樣得到,然后每次用 k ? 1 k - 1 k?1 個子集的并集作為訓練集,余下的那個子集作為驗證集;這樣就可以獲得 k k k 組訓練 / / /驗證集,從而可以進行 k k k 次訓練和驗證,最侄訓傳的是這 k k k 個結果的均值, 該方法又稱為 k k k 折交叉驗證(k-fold cross validation), k k k 常用的取值為 5 , 10 , 20 5,10,20 5,10,20 等,

( 留 一 法 ) ?? \textcolor{purple}{(留一法)}\; () k = ∣ D ∣ k=|D| k=D,則得到了交叉驗證法的一個特例:留一法(Leave-One-Out,簡稱LOO),LOO使用的訓練集與初始資料集相比只少了一個樣本,這就使得在絕大多數情況下,LOO中被實際評估的模型與期望評估的用 D D D 訓練出的模型很相似,因此,LOO的評估結果往往被認為比較準確,但LOO也有缺陷: ∣ D ∣ |D| D 較大時,訓練 ∣ D ∣ |D| D 個模型的計算開銷可能是難以忍受的(這還是在未考慮調參的情況下),

1.3 sklearn.model_selection.train_test_split()

該函式的主要作用是將現有的資料集隨機劃分成訓練集和測驗集,其主要引數如下:

t r a i n _ t e s t _ s p l i t ( X , y , t e s t _ s i z e = N o n e , t r a i n _ s i z e = N o n e , r a n d o m _ s t a t e = N o n e ) \mathrm{train\_test\_split(X, y, test\_size=None, train\_size=None, random\_state=None)} train_test_split(X,y,test_size=None,train_size=None,random_state=None)

引數描述
X示例矩陣
y標簽向量
test_size可以為浮點數整數;當為浮點數時,表示測驗集在整個資料集中所占的比例,當為整數時,表示測驗集的大小;當test_size和train_size都為None時,test_size默認調整至0.25
train_size同上;當train_size為None時,默認調整至測驗集的補集的大小

對示例矩陣和標簽向量不了解的讀者可參考我的上一篇文章,

該函式會回傳一個串列 [ X _ t r a i n , X _ t e s t , y _ t r a i n , y _ t e s t ] [X\_train, X\_test, y\_train, y\_test] [X_train,X_test,y_train,y_test],我們只需要用相應的四個引數去接收即可,

from sklearn.model_selection import train_test_split

X = [[1, 2], [2, 3], [3, 3], [2, 1], [3, 2]]
y = [1, 1, 1, -1, -1]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.4, random_state=42)
print(X_train)
# [[3, 3], [1, 2], [2, 1]]
print(X_test)
# [[2, 3], [3, 2]]
print(y_train)
# [1, 1, -1]
print(y_test)
# [1, -1]

1.4 sklearn.metrics.accuracy_score()

在進一步講解有關交叉驗證的函式之前,我們先來講一下有關性能度量的函式,

我們已經知道,SVC類的score方法 clf.score() 可以用來計算模型在測驗集上的分類準確率,例如:

from sklearn.model_selection import train_test_split
from sklearn.datasets import make_blobs
from sklearn.svm import SVC

X, y = make_blobs(n_samples=500, centers=2, random_state=34)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)
clf = SVC(kernel='linear')
clf.fit(X_train, y_train)
print(clf.score(X_test, y_test))
# 0.912

即分類準確率為 91.2 % 91.2\% 91.2%

accuracy_score的使用方法: a c c u r a c y _ s c o r e ( y _ t r u e , y _ p r e d ) \mathrm{accuracy\_score(y\_true, y\_pred)} accuracy_score(y_true,y_pred),其中 y_true 是真實的標簽串列,而 y_pred 是預測的標簽串列,

from sklearn.model_selection import train_test_split
from sklearn.datasets import make_blobs
from sklearn.svm import SVC
from sklearn.metrics import accuracy_score

X, y = make_blobs(n_samples=500, centers=2, random_state=34)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)
clf = SVC(kernel='linear')
clf.fit(X_train, y_train)
y_pred = clf.predict(X_test)
print(accuracy_score(y_test, y_pred))
# 0.912

看到這里,可能會有讀者疑惑,clf.scoreaccuracy_score 的結果一樣,那它們之間到底有什么區別呢?

1.4.1 clf.score 與 accuracy_score 的區別

不嚴謹地來講,accuracy_score 僅僅是按序比較兩個串列(array_like 物件),然后回傳相同元素的個數所占的比例:

from sklearn.metrics import accuracy_score

A = [1, 2, 3, 4]
B = [2, 2, 3, 5]
C = [4, 3, 2, 1]
print(accuracy_score(A, B))
# 0.5
print(accuracy_score(A, C))
# 0.4

從第二個輸出可以看出,雖然兩個串列的內容相同,但因為 accuracy_score 是按序(索引)進行比較的,所以準確率為 0 0 0;從第一個輸出可以看出,兩個串列只有索引 1 1 1 2 2 2 處的元素相同,所以準確率為 2 / 4 = 0.5 2/4=0.5 2/4=0.5

再來看看 clf.score,其底層實作為

def score(self, X, y, sample_weight=None):
	from .metrics import accuracy_score
    return accuracy_score(y, self.predict(X), sample_weight=sample_weight)

可以看出本質上和 accuracy_score 沒有什么區別,但 clf.score 使用起來更為方便,因此更加推薦,

1.5 sklearn.model_selection.cross_val_score()

我們已經知道, k k k 折交叉驗證一共會產生 k k k 個得分(這些得分的均值作為交叉驗證的得分),而 cross_val_score() 回傳的就是這 k k k 個得分,

該函式主要有以下引數:

c r o s s _ v a l _ s c o r e ( e s t i m a t o r , X , y , s c o r i n g = N o n e , c v = N o n e ) \mathrm{cross\_val\_score(estimator, X, y, scoring=None, cv=None)} cross_val_score(estimator,X,y,scoring=None,cv=None)

引數描述
estimatorSVM任務下就是SVC實體
scoring性能度量;默認值為None,即采用SVC類中的score方法;有關scoring的可選引數請見官方檔案
cv k k k 折交叉驗證中的 k k k;默認值為None,即采用 5 5 5 折交叉驗證
from sklearn.datasets import make_blobs
from sklearn.svm import SVC
from sklearn.model_selection import cross_val_score

X, y = make_blobs(n_samples=500, centers=2, random_state=34)
clf = SVC(kernel='linear')
print(cross_val_score(clf, X, y, cv=3))
# [0.94011976 0.94011976 0.93373494]
print(cross_val_score(clf, X, y, cv=3, scoring='accuracy'))
# [0.94011976 0.94011976 0.93373494]

該例子也進一步說明了 clf.scoreaccuracy_score 是一樣的,

scores = cross_val_score(clf, X, y, cv=3)
print("%.4f accuracy with a standard deviation of %.4f" % (scores.mean(), scores.std()))
# 0.938 accuracy with a standard deviation of 0.003

即我們交叉驗證的得分為 0.938 0.938 0.938

基于此,我們可以使用 cross_val_score 來選擇最優引數:

from sklearn.datasets import make_blobs
from sklearn.svm import SVC
from sklearn.model_selection import cross_val_score

X, y = make_blobs(n_samples=500, centers=2, random_state=34)
for C in [1, 10, 100, 1000, 10000, 100000]:
    clf = SVC(C=C, kernel='linear')
    scores = cross_val_score(clf, X, y, cv=4)  # 四折交叉驗證
    print('C: %d, accuracy: %.3f' % (C, scores.mean()))
# C: 1, accuracy: 0.936
# C: 10, accuracy: 0.936
# C: 100, accuracy: 0.936
# C: 1000, accuracy: 0.938
# C: 10000, accuracy: 0.938
# C: 100000, accuracy: 0.940

從輸出結果可以看出, C = 100000 C=100000 C=100000 是這六個引數中的最優引數(不過要注意的是,我們是直接將原有的資料集劃分為訓練集和驗證集,并未劃分出測驗集),

正確的流程應該是:先將原有的資料集劃分為訓練集和測驗集,在訓練集上進行 k k k 折交叉驗證來選取最優引數,得到最優引數后,在訓練集上訓練模型,在測驗集上測驗性能,完整的代碼如下:

from sklearn.datasets import make_blobs
from sklearn.svm import SVC
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import train_test_split

# 初始化
X, y = make_blobs(n_samples=500, centers=2, random_state=34)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
params = [1, 10, 100, 1000, 10000, 100000, 1000000]
params_score = []

# 尋找最優引數
for C in params:
    clf = SVC(C=C, kernel='linear')
    scores = cross_val_score(clf, X_train, y_train, cv=4)
    params_score.append(scores.mean())
best_param = params[params_score.index(max(params_score))]

# 重新訓練
clf_best = SVC(C=best_param, kernel='linear')
clf_best.fit(X_train, y_train)

# 測驗性能
accuracy = clf_best.score(X_test, y_test)
print(best_param)
# 1000000
print(accuracy)
# 0.95

可以看出,我們使用最優引數訓練出來的模型在測驗集上的分類準確率為 95 % 95\% 95%

二、網格搜索法

網格搜索法的本質是遍歷

2.1 網格搜索法的由來

在訓練線性核軟間隔SVM時,會涉及到超引數 C C C,選取合適的 C C C 值能夠使我們訓練出來的模型最優,那么該如何去尋找這個最合適的 C C C 值呢?

一個很自然的想法就是把 C C C 的所有取值都試一遍,用交叉驗證法對每一個 C C C 值打分,得分最高的 C C C 成為我們的最優引數,但現實中,我們的引數一般都是連續取值的,我們不可能去遍歷所有的 C C C 值,因此只能考慮有限個 C C C 值,考慮到 C C C 一般較大,我們可以假設 C C C 的取值集合為

C = { 1 , 10 , 1 0 2 , ? ? , 1 0 6 } \boldsymbol C=\{1,10,10^2,\cdots,10^6\} C={1,10,102,?,106}

于是我們只需要去遍歷集合 C \boldsymbol C C

現在考慮高斯核的情形,這時候會涉及到兩個引數: ( C , γ ) (C,\gamma) (C,γ),因為 γ \gamma γ 取值一般較小,我們可以假設它的取值集合為

γ = { 1 0 ? 6 , 1 0 ? 5 , ? ? , 1 0 ? 1 , 1 } \boldsymbol \gamma =\{10^{-6}, 10^{-5},\cdots,10^{-1},1\} γ={10?6,10?5,?,10?1,1}

現在作笛卡爾積 C × γ \boldsymbol C\times \boldsymbol\gamma C×γ,則該集合的大小為 ∣ C ∣ ? ∣ γ ∣ |\boldsymbol C|\cdot|\boldsymbol \gamma| C?γ,且其中元素的形式為 ( C , γ ) (C,\gamma) (C,γ),遍歷 C × γ \boldsymbol C\times \boldsymbol\gamma C×γ 就相當于遍歷 ( C , γ ) (C,\gamma) (C,γ) 所有可能的組合,注意到 C × γ \boldsymbol C\times \boldsymbol\gamma C×γ 還可以用 “網格” 來進行表示:

C = 1 C=1 C=1 C = 10 C=10 C=10 ? \cdots ? C = 1 0 6 C=10^6 C=106
γ = 1 0 ? 6 \gamma=10^{-6} γ=10?6 ( C = 1 , γ = 1 0 ? 6 ) (C=1, \gamma=10^{-6}) (C=1,γ=10?6) ( C = 10 , γ = 1 0 ? 6 ) (C=10, \gamma=10^{-6}) (C=10,γ=10?6) ? \cdots ? ( C = 1 0 6 , γ = 1 0 ? 6 ) (C=10^6, \gamma=10^{-6}) (C=106,γ=10?6)
γ = 1 0 ? 5 \gamma=10^{-5} γ=10?5 ( C = 1 , γ = 1 0 ? 5 ) (C=1, \gamma=10^{-5}) (C=1,γ=10?5) ( C = 10 , γ = 1 0 ? 5 ) (C=10, \gamma=10^{-5}) (C=10,γ=10?5) ? \cdots ? ( C = 1 0 6 , γ = 1 0 ? 5 ) (C=10^6, \gamma=10^{-5}) (C=106,γ=10?5)
? \vdots ? ? \vdots ? ? \vdots ? ? \cdots ? ? \vdots ?
γ = 1 \gamma=1 γ=1 ( C = 1 , γ = 1 ) (C=1, \gamma=1) (C=1,γ=1) ( C = 10 , γ = 1 ) (C=10, \gamma=1) (C=10,γ=1) ? \cdots ? ( C = 1 0 6 , γ = 1 ) (C=10^6, \gamma=1) (C=106,γ=1)

因此遍歷 C × γ \boldsymbol C\times \boldsymbol\gamma C×γ 就相當于遍歷上面的網格,又因為我們需要在網格中找出最優引數,故該方法又稱網格搜索法

不難看出,網格搜索法的本質就是暴力遍歷,即把每一種情況都試一遍,然后找出最優的那個,

2.2 使用 for 回圈實作網格搜索

因為網格搜索的本質是遍歷,所以我們完全可以使用 for 回圈來實作這種遍歷,

事實上,1.5 節中的最后一個例子就用到了網格搜索法,不過我們當時也僅僅是遍歷了一個引數的取值集合,現在我們考慮兩個引數的情形,即使用高斯核的軟間隔SVM,

from sklearn.datasets import make_blobs
from sklearn.svm import SVC
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import train_test_split

# 初始化
X, y = make_blobs(n_samples=500, centers=2, random_state=34)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
best_score = 0

# 尋找最優引數
for C in [1, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6]:
    for gamma in [1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1]:
        clf = SVC(C=C, gamma=gamma)
        cv_scores = cross_val_score(clf, X_train, y_train, cv=4)
        current_score = cv_scores.mean()
        if current_score > best_score:
            best_score = current_score
            best_parameters = {'C': C, 'gamma': gamma}

# 重新訓練
clf_best = SVC(**best_parameters)
clf_best.fit(X_train, y_train)

# 測驗性能
accuracy = clf_best.score(X_test, y_test)
print(best_parameters)
# {'C': 100000.0, 'gamma': 0.01}
print(accuracy)
# 0.94

輸出結果表明,最優引數為 ( C = 100000 , γ = 0.01 ) (C=100000, \gamma=0.01) (C=100000,γ=0.01),最終的分類準確率為 94 % 94\% 94%

2.3 sklearn.model_selection.GridSearchCV()

看到這里可能有讀者會想,雖然 for 回圈是可以實作網格搜索,那有沒有更簡便快捷的方法呢?好在 sklearn 提供了這樣的一個類:sklearn.model_selection.GridSearchCV,它結合了網格搜索與交叉驗證,能夠方便地給出你想要的結果,

2.3.1 引數

創建一個 GridSearchCV 實體常用到以下引數:

G r i d S e a r c h C V ( e s t i m a t o r , p a r a m _ g r i d , s c o r i n g = N o n e , r e f i t = T r u e , c v = N o n e ) \mathrm{GridSearchCV(estimator, param\_grid, scoring=None, refit=True,cv=None)} GridSearchCV(estimator,param_grid,scoring=None,refit=True,cv=None)


e s t i m a t o r : \textcolor{blue}{\mathrm{estimator:}} estimator:

在SVM場景下,estimator 指的是SVC實體,因為后續我們還需要向 GridSearchCV() 中傳入引數網格,所以創建SVC實體的時候不需要任何引數,即:

estimator = SVC()
clf = GridSearchCV(estimator, ...)

甚至可以更簡便地寫成

clf = GridSearchCV(SVC(), ...)

p a r a m _ g r i d : \textcolor{blue}{\mathrm{param\_grid:}} param_grid:

引數網格,可以為字典字典串列

例如對于2.2節中的例子,我們的引數網格就是一個字典:

param_grid = {
    'C': [1, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6], 
    'gamma': [1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1],
}

該情形一共有 7 × 7 = 49 7\times7=49 7×7=49 種引陣列合,

對于某些復雜的任務,我們可能需要用到字典串列:

param_grid = [
    {"kernel": ["rbf"], "gamma": [1e-3, 1e-4], "C": [1, 10, 100, 1000]},
    {"kernel": ["linear"], "C": [1, 10, 100, 1000]},
]

該情形一共有 1 × 2 × 4 ? + ? 1 × 4 = 12 1\times 2\times4\,+\,1\times 4=12 1×2×4+1×4=12 種引陣列合,


s c o r i n g : \textcolor{blue}{\mathrm{scoring:}} scoring:

性能度量,默認值為None,常用引數為 'accuracy'


r e f i t : \textcolor{blue}{\mathrm{refit:}} refit:

默認值為 True

refit 為 True 時,程式會使用得到的最優引數原先的訓練集上重新訓練,結果會存盤在 GridSearchCV 實體的 best_estimator_ 屬性中(注意,best_estimator_已經擬合了的 estimator),

2.3.2 方法

本小節僅列出最常用的三個方法,其他方法可自行參閱官方檔案,

方法描述
fit(X, y)基于所有引陣列合擬合estimator
predict(X)使用最優模型預測樣本;當 refit=True 時才可用
score(X_test, y_test)除非 scoring 給定,否則采用 best_estimator_.score 方法計算得分

現在,我們將使用 GridSearchCV 來簡化2.2節中的代碼,

from sklearn.datasets import make_blobs
from sklearn.svm import SVC
from sklearn.model_selection import train_test_split
from sklearn.model_selection import GridSearchCV

X, y = make_blobs(n_samples=500, centers=2, random_state=34)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
param_grid = {
    'C': [1, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6], 
    'gamma': [1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1],
}

clf = GridSearchCV(SVC(), param_grid, cv=4)
clf.fit(X_train, y_train)
print(clf.score(X_test, y_test))
# 0.94

輸出結果與2.2節中的一致,但代碼大大得到了簡化,

2.3.3 屬性

這里僅列出常用的屬性,

屬性描述
cv_results_以字典形式回傳交叉驗證的結果
best_estimator_使用最優引數在原先的訓練集上重新訓練得到的estimator
best_score_best_estimator的交叉驗證的得分(均值)
best_params_best_estimator中的引數
best_index_best_params在 clf.cv_results_['params'] 中的索引

接下來我們通過一些例子進一步熟悉這些屬性,

為了簡便起見,我們將引數網格設定的 “小” 一點,其他不變

......

param_grid = {
    'C': [1e4, 1e5], 
    'gamma': [1e-2, 1e-1],
}

......

print(clf.cv_results_)

輸出為:

{
    'mean_fit_time': array([0.00424391, 0.01795793, 0.02118272, 0.12142873]), 
    'std_fit_time': array([0.00044348, 0.00522967, 0.00470208, 0.01951696]), 
    'mean_score_time': array([0.        , 0.00074494, 0.0007624 , 0.00074446]), 
    'std_score_time': array([0.        , 0.00043013, 0.00044034, 0.00042986]), 
    'param_C': masked_array(data=[10000.0, 10000.0, 100000.0, 100000.0],
             mask=[False, False, False, False], fill_value='?', dtype=object), 
    'param_gamma': masked_array(data=[0.01, 0.1, 0.01, 0.1],
             mask=[False, False, False, False], fill_value='?', dtype=object), 
    'params': [{'C': 10000.0, 'gamma': 0.01}, {'C': 10000.0, 'gamma': 0.1}, 
               {'C': 100000.0, 'gamma': 0.01}, {'C': 100000.0, 'gamma': 0.1}], 
    'split0_test_score': array([0.94, 0.94, 0.95, 0.94]), 
    'split1_test_score': array([0.93, 0.95, 0.94, 0.94]), 
    'split2_test_score': array([0.97, 0.95, 0.98, 0.95]), 
    'split3_test_score': array([0.94, 0.94, 0.93, 0.93]), 
    'mean_test_score': array([0.945, 0.945, 0.95 , 0.94 ]), 
    'std_test_score': array([0.015     , 0.005     , 0.01870829, 0.00707107]), 
    'rank_test_score': array([2, 2, 1, 4])
}

注意:

  • 'params' 中存盤了所有的引陣列合,
  • mean_fit_time, std_fit_time, mean_score_timestd_score_time 的單位均是
print(clf.best_estimator_)
# SVC(C=100000.0, gamma=0.01)
print(clf.best_params_)
# {'C': 100000.0, 'gamma': 0.01}
print(clf.best_index_)
# 2
print(clf.best_score_)
# 0.9500000000000001

不難看出,clf.best_estimator_ 等價于 SVC(**clf.best_params_),且最優引數 clf.best_params_ 在串列 clf.cv_results_['params'] 中的索引為 2,即

print(clf.cv_results_['params'][clf.best_index_] == clf.best_params_)
# True

三、專案實戰——鳶尾花分類

3.1 鳶尾花資料集介紹

sklearn 中有現成的鳶尾花資料集,我們可以從其中的 datasets 匯入加載鳶尾花資料集的函式:

from sklearn.datasets import load_iris

鳶尾花資料集介紹:

可以看出我們將面臨的問題是一個多(三)分類問題,

3.2 sklearn.datasets.load_iris()

該函式最主要的引數只有一個:return_X_y


r e t u r n _ X _ y : \textcolor{blue}{\mathrm{return\_X\_y:}} return_X_y:

默認值為 False

當值為 True 時,load_iris() 將回傳元組 (data, target) (即 (X, y) ),否則將以 Bunch 物件(類字典物件)回傳,

這里建議將 return_X_y 設定為 True,這樣我們就能很方便地使用兩個引數進行接收:

X, y = load_iris(return_X_y=True)

如果設定為 False (即默認狀態),我們就只能:

iris = load_iris()
X, y = iris.data, iris.target

3.3 代碼實作

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.model_selection import GridSearchCV
from sklearn.svm import SVC

X, y = load_iris(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0)
param_grid = {
    'C': [1, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6],
    'kernel': ['rbf', 'linear'],
    'gamma': [1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1],
}

clf = GridSearchCV(SVC(), param_grid, cv=5)
clf.fit(X_train, y_train)
print(clf.best_params_)
# {'C': 10.0, 'gamma': 0.1, 'kernel': 'rbf'}
print(clf.score(X_test, y_test))
# 0.9777777777777777

使用五折交叉驗證,我們的最優引數為 ( C = 10 , γ = 0.1 ) (C=10, \gamma=0.1) (C=10,γ=0.1),且核為高斯核,最終模型在測驗集上的分類準確率為 97.8 % 97.8\% 97.8%

References

[1] Cross-validation: evaluating estimator performance.
[2] Tuning the hyper-parameters of an estimator.
[3] sklearn.datasets.load_iris.
[4] 機器學習. 周志華

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/423959.html

標籤:AI

上一篇:python機器學習之流水線

下一篇:OpenCV-Python實戰(19)——OpenCV與深度學習的碰撞

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more