隨機森林在乳腺癌數據上的調參

  這篇文章中,使用基於方差和誤差的調參方法,在乳腺癌數據上進行一次隨機森林的調參。乳腺癌數據是sklearn自帶的分類數據之一。node

  案例中,每每使用真實數據,爲何咱們要使用sklearn自帶的數據呢?由於真實數據在隨機森林下的調參過程,每每很是緩慢。真實數據量大,維度高,在使用隨機森林以前須要一系列的處理,所以不太適合用來作直播中的案例演示。本來,我爲你們準備了kaggle上下載的辨別手寫數字的數據,有4W多條記錄700多個左右的特徵,隨機森林在這個辨別手寫數字的數據上有很是好的表現,其調參案例也是很是經典,可是因爲數據的維度過高,太過複雜,運行一次完整的網格搜索須要四五個小時,所以不太可能拿來給你們進行演示。經典的泰坦尼克號數據,用來調參的話也是須要很長時間,所以我才選擇sklearn當中自帶的,結構相對清晰簡單的數據來爲你們作這個案例。你們感興趣的話,能夠直接到kaggle上進行下載,數據集名稱是Digit Recognizer(https://www.kaggle.com/c/digit-recognizer)。git

  那咱們接下來,就用乳腺癌數據,來看看咱們的調參代碼。算法

1. 導入須要的庫

1 from sklearn.datasets import load_breast_cancer
2 from sklearn.ensemble import RandomForestClassifier
3 from sklearn.model_selection import GridSearchCV
4 from sklearn.model_selection import cross_val_score
5 import matplotlib.pyplot as plt
6 import pandas as pd
7 import numpy as np
 

2. 導入數據集,探索數據

1 data = load_breast_cancer()
2 3 data
4 5 data.data.shape
6 7 data.target

 

 

  能夠看到,乳腺癌數據集有569條記錄,30個特徵,單看維度雖然不算過高,可是樣本量很是少。過擬合的狀況可能存在。數組

3. 簡單建模

  咱們先進行一次簡單的建模,看看模型自己在數據集上的效果app

1 rfc = RandomForestClassifier(n_estimators=100,random_state=90)
2 score_pre = cross_val_score(rfc,data.data,data.target,cv=10).mean()
3 score_pre

 

這裏能夠看到,隨機森林在乳腺癌數據上的表現本就還不錯,在現實數據集上,基本上不可能什麼都不調就看到95%以上的準確率。dom

4. 調參第一步:不管如何先來調n_estimators

在這裏咱們選擇學習曲線,可使用網格搜索嗎?能夠,可是隻有學習曲線,才能看見趨勢 我我的的傾向是,要看見n_estimators在什麼取值開始變得平穩,是否一直推進模型總體準確率的上升等信息 第一次的學習曲線,能夠先用來幫助咱們劃定範圍,咱們取每十個數做爲一個階段,來觀察n_estimators的變化如何引發模型總體準確率的變化機器學習

 1 #####【TIME WARNING: 30 seconds】#####
 2  3 scorel = []
 4 for i in range(0,200,10):
 5     rfc = RandomForestClassifier(n_estimators=i+1,
 6                                  n_jobs=-1,
 7                                  random_state=90)
 8     score = cross_val_score(rfc,data.data,data.target,cv=10).mean()
 9     scorel.append(score)
10 print(max(scorel),(scorel.index(max(scorel))*10)+1)
11 plt.figure(figsize=[20,5])
12 plt.plot(range(1,201,10),scorel)
13 plt.show()
14 15 #list.index([object]),返回這個object在列表list中的索引

 

  從運行結果來看,當n_estimators=41的時候score取得最大值0.968。學習

5. 調參第二步:細化學習曲線

  在肯定好的範圍內,進一步細化學習曲線spa

 1 scorel = []
 2 for i in range(35,45):
 3     rfc = RandomForestClassifier(n_estimators=i,
 4                                  n_jobs=-1,
 5                                  random_state=90)
 6     score = cross_val_score(rfc,data.data,data.target,cv=10).mean()
 7     scorel.append(score)
 8 print(max(scorel),([*range(35,45)][scorel.index(max(scorel))]))
 9 plt.figure(figsize=[20,5])
10 plt.plot(range(35,45),scorel)
11 plt.show()

 

  調整n_estimators的效果顯著,模型的準確率馬上上升了0.005。接下來就進入網格搜索,咱們將使用網格搜索對參數一個個進行調整。爲何咱們不一樣時調整多個參數呢?緣由有兩個:1)同時調整多個參數會運行很是緩慢,在課堂上咱們沒有這麼多的時間。2)同時調整多個參數,會讓咱們沒法理解參數的組合是怎麼得來的,因此即使網格搜索調出來的結果很差,咱們也不知道從哪裏去改。在這裏,爲了使用複雜度-泛化偏差方法(方差-誤差方法),咱們對參數進行一個個地調整。3d

6. 書寫網格搜索的參數

  書寫網格搜索的參數,爲網格搜索作準備。

  有一些參數是沒有參照的,很難說清一個範圍,這種狀況下咱們使用學習曲線,看趨勢 從曲線跑出的結果中選取一個更小的區間,再跑曲線

1 param_grid = {'n_estimators':np.arange(0, 200, 10)}
2 3 param_grid = {'max_depth':np.arange(1, 20, 1)}
4 5 param_grid = {'max_leaf_nodes':np.arange(25,50,1)}
6 #對於大型數據集,能夠嘗試從1000來構建,先輸入1000,每100個葉子一個區間,再逐漸縮小範圍

  有一些參數是能夠找到一個範圍的,或者說咱們知道他們的取值和隨着他們的取值,模型的總體準確率會如何變化,這樣的參數咱們就能夠直接跑網格搜索

1 param_grid = {'criterion':['gini', 'entropy']}
2 3 param_grid = {'min_samples_split':np.arange(2, 2+20, 1)}
4 5 param_grid = {'min_samples_leaf':np.arange(1, 1+10, 1)}
6     
7 param_grid = {'max_features':np.arange(5,30,1)}

 

7. 調整max_depth

  開始按照參數對模型總體準確率的影響程度進行調參,首先調整max_depth

 1 #調整max_depth
 2  3 param_grid = {'max_depth':np.arange(1, 20, 1)}
 4  5 #   通常根據數據的大小來進行一個試探,乳腺癌數據很小,因此能夠採用1~10,或者1~20這樣的試探
 6 #   但對於像digit recognition那樣的大型數據來講,咱們應該嘗試30~50層深度(或許還不足夠
 7 #   更應該畫出學習曲線,來觀察深度對模型的影響
 8  9 rfc = RandomForestClassifier(n_estimators=39
10                              ,random_state=90
11                             )
12 GS = GridSearchCV(rfc,param_grid,cv=10)
13 GS.fit(data.data,data.target)
14 15 GS.best_params_
16 17 GS.best_score_

 

  在這裏,咱們注意到,將max_depth設置爲有限以後,模型的準確率降低了。限制max_depth,是讓模型變得簡單,把模型向左推,而模型總體的準確率降低了,即總體的泛化偏差上升了,這說明模型如今位於圖像左邊,即泛化偏差最低點的左邊(誤差爲主導的一邊)。一般來講,隨機森林應該在泛化偏差最低點的右邊,樹模型應該傾向於過擬合,而不是擬合不足。這和數據集自己有關,但也有多是咱們調整的n_estimators對於數據集來講太大,所以將模型拉到泛化偏差最低點去了。然而,既然咱們追求最低泛化偏差,那咱們就保留這個n_estimators,除非有其餘的因素,能夠幫助咱們達到更高的準確率。

  當模型位於圖像左邊時,咱們須要的是增長模型複雜度(增長方差,減小誤差)的選項,所以max_depth應該儘可能大,min_samples_leaf和min_samples_split都應該儘可能小。這幾乎是在說明,除了max_features,咱們沒有任何參數能夠調整了,由於max_depth,min_samples_leaf和min_samples_split是剪枝參數,是減少複雜度的參數。在這裏,咱們能夠預言,咱們已經很是接近模型的上限,模型極可能沒有辦法再進步了。

  那咱們這就來調整一下max_features,看看模型如何變化。

8. 調整max_features

  max_features是惟一一個即可以將模型往左(低方差高誤差)推,也可以將模型往右(高方差低誤差)推的參數。咱們須要根據調參前,模型所在的位置(在泛化偏差最低點的左邊仍是右邊)來決定咱們要將max_features往哪邊調。如今模型位於圖像左側,咱們須要的是更高的複雜度,所以咱們應該把max_features往更大的方向調整,可用的特徵越多,模型纔會越複雜。max_features的默認最小值是sqrt(n_features),所以咱們使用這個值做爲調參範圍的最小值。

 1 #調整max_features
 2 param_grid = {'max_features':np.arange(5,30,1)} 
 3  4 rfc = RandomForestClassifier(n_estimators=39
 5                              ,random_state=90
 6                             )
 7 GS = GridSearchCV(rfc,param_grid,cv=10)
 8 GS.fit(data.data,data.target)
 9 10 GS.best_params_
11 12 GS.best_score_

 

  網格搜索返回了max_features的最小值,可見max_features升高以後,模型的準確率下降了。這說明,咱們把模型往右推,模型的泛化偏差增長了。前面用max_depth往左推,如今用max_features往右推,泛化偏差都增長,這說明模型自己已經處於泛化偏差最低點,已經達到了模型的預測上限,沒有參數能夠左右的部分了。剩下的那些偏差,是噪聲決定的,已經沒有方差和誤差的舞臺了。

  若是是現實案例,咱們到這一步其實就能夠停下了,由於複雜度和泛化偏差的關係已經告訴咱們,模型不能再進步了。調參和訓練模型都須要很長的時間,明知道模型不能進步了還繼續調整,不是一個有效率的作法。若是咱們但願模型更進一步,咱們會選擇更換算法,或者更換作數據預處理的方式。可是在課上,出於練習和探索的目的,咱們繼續調整咱們的參數,讓你們觀察一下模型的變化,看看咱們預測得是否正確。

  依然按照參數對模型總體準確率的影響程度進行調參。

9. 調整min_samples_leaf

  對於min_samples_split和min_samples_leaf,通常是從他們的最小值開始向上增長10或20 面對高維度高樣本量數據,若是不放心,也能夠直接+50,對於大型數據,可能須要200~300的範圍 若是調整的時候發現準確率不管如何都上不來,那能夠放心大膽調一個很大的數據,大力限制模型的複雜度

 1 #調整min_samples_leaf
 2 param_grid={'min_samples_leaf':np.arange(1, 1+10, 1)}
 3  4 rfc = RandomForestClassifier(n_estimators=39
 5                              ,random_state=90
 6                             )
 7 GS = GridSearchCV(rfc,param_grid,cv=10)
 8 GS.fit(data.data,data.target)
 9 10 GS.best_params_
11 12 GS.best_score_

 

  能夠看見,網格搜索返回了min_samples_leaf的最小值,而且模型總體的準確率還下降了,這和max_depth的狀況一致,參數把模型向左推,可是模型的泛化偏差上升了。在這種狀況下,咱們顯然是不要把這個參數設置起來的,就讓它默認就行了。

10. 調整min_samples_split

  不懈努力,繼續嘗試min_samples_split

 1 #調整min_samples_split
 2 param_grid={'min_samples_split':np.arange(2, 2+20, 1)}
 3  4 rfc = RandomForestClassifier(n_estimators=39
 5                              ,random_state=90
 6                             )
 7 GS = GridSearchCV(rfc,param_grid,cv=10)
 8 GS.fit(data.data,data.target)
 9 10 GS.best_params_
11 12 GS.best_score_

 

  和min_samples_leaf同樣的結果,返回最小值而且模型總體的準確率下降了。

11. 調整criterion

  最後嘗試一下criterion

 1 #調整Criterion
 2 param_grid = {'criterion':['gini', 'entropy']}
 3  4 rfc = RandomForestClassifier(n_estimators=39
 5                              ,random_state=90
 6                             )
 7 GS = GridSearchCV(rfc,param_grid,cv=10)
 8 GS.fit(data.data,data.target)
 9 10 GS.best_params_
11 12 GS.best_score_

 

12. 總結最佳參數

  調整完畢,總結出模型的最佳參數

1 rfc = RandomForestClassifier(n_estimators=39,random_state=90)
2 score = cross_val_score(rfc,data.data,data.target,cv=10).mean()
3 score
4 5 score - score_pre

 

  在整個調參過程之中,咱們首先調整了n_estimators(不管如何都請先走這一步),而後調整max_depth,經過max_depth產生的結果,來判斷模型位於複雜度-泛化偏差圖像的哪一邊,從而選擇咱們應該調整的參數和調參的方向。若是感到困惑,也能夠畫不少學習曲線來觀察參數會如何影響咱們的準確率,選取學習曲線中單調的部分來放大研究(如同咱們對n_estimators作的)。學習曲線的拐點也許就是咱們一直在追求的,最佳複雜度對應的泛化偏差最低點(也是方差和誤差的平衡點)。

  網格搜索也能夠一塊兒調整多個參數,你們只要有時間,能夠本身跑一下,看看網格搜索會給咱們怎樣的結果,有時候,它的結果比咱們的好,有時候,咱們手動調整的結果會比較好。固然了,咱們的乳腺癌數據集很是完美,因此只須要調n_estimators一個參數就達到了隨機森林在這個數據集上表現得極限。在咱們上週使用的泰坦尼克號案例的數據中,咱們使用一樣的方法調出了以下的參數組合。

1 rfc = RandomForestClassifier(n_estimators=68
2                              ,random_state=90
3                              ,criterion="gini"
4                              ,min_samples_split=8
5                              ,min_samples_leaf=1
6                              ,max_depth=12
7                              ,max_features=2
8                              ,max_leaf_nodes=36
9                              )

  基於泰坦尼克號數據調整出來的參數,這個組合的準確率達到了83.915%,比單棵決策樹提高了大約7%,比調參前的隨機森林提高了2.02%,這對於調參來講實際上是一個很是巨大的進步。不過,泰坦尼克號數據的運行緩慢,你們量力量時間而行,能夠試試看用複雜度-泛化偏差方法(方差-誤差方法)來解讀一下這個調參結果和過程。

  好了調參的步驟到這裏就結束了,感興趣的小夥伴們本身去敲一下代碼吧,學習機器學習最重要的就是要多動手練習一下代碼,多敲幾遍熟悉了就行了,加油。

相關文章
相關標籤/搜索