這篇文章中,使用基於方差和誤差的調參方法,在乳腺癌數據上進行一次隨機森林的調參。乳腺癌數據是sklearn自帶的分類數據之一。node
案例中,每每使用真實數據,爲何咱們要使用sklearn自帶的數據呢?由於真實數據在隨機森林下的調參過程,每每很是緩慢。真實數據量大,維度高,在使用隨機森林以前須要一系列的處理,所以不太適合用來作直播中的案例演示。本來,我爲你們準備了kaggle上下載的辨別手寫數字的數據,有4W多條記錄700多個左右的特徵,隨機森林在這個辨別手寫數字的數據上有很是好的表現,其調參案例也是很是經典,可是因爲數據的維度過高,太過複雜,運行一次完整的網格搜索須要四五個小時,所以不太可能拿來給你們進行演示。經典的泰坦尼克號數據,用來調參的話也是須要很長時間,所以我才選擇sklearn當中自帶的,結構相對清晰簡單的數據來爲你們作這個案例。你們感興趣的話,能夠直接到kaggle上進行下載,數據集名稱是Digit Recognizer(https://www.kaggle.com/c/digit-recognizer)。git
那咱們接下來,就用乳腺癌數據,來看看咱們的調參代碼。算法
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
1 data = load_breast_cancer() 2 3 data 4 5 data.data.shape 6 7 data.target
能夠看到,乳腺癌數據集有569條記錄,30個特徵,單看維度雖然不算過高,可是樣本量很是少。過擬合的狀況可能存在。數組
咱們先進行一次簡單的建模,看看模型自己在數據集上的效果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
在這裏咱們選擇學習曲線,可使用網格搜索嗎?能夠,可是隻有學習曲線,才能看見趨勢 我我的的傾向是,要看見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。學習
在肯定好的範圍內,進一步細化學習曲線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
書寫網格搜索的參數,爲網格搜索作準備。
有一些參數是沒有參照的,很難說清一個範圍,這種狀況下咱們使用學習曲線,看趨勢 從曲線跑出的結果中選取一個更小的區間,再跑曲線
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)}
開始按照參數對模型總體準確率的影響程度進行調參,首先調整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,看看模型如何變化。
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往右推,泛化偏差都增長,這說明模型自己已經處於泛化偏差最低點,已經達到了模型的預測上限,沒有參數能夠左右的部分了。剩下的那些偏差,是噪聲決定的,已經沒有方差和誤差的舞臺了。
若是是現實案例,咱們到這一步其實就能夠停下了,由於複雜度和泛化偏差的關係已經告訴咱們,模型不能再進步了。調參和訓練模型都須要很長的時間,明知道模型不能進步了還繼續調整,不是一個有效率的作法。若是咱們但願模型更進一步,咱們會選擇更換算法,或者更換作數據預處理的方式。可是在課上,出於練習和探索的目的,咱們繼續調整咱們的參數,讓你們觀察一下模型的變化,看看咱們預測得是否正確。
依然按照參數對模型總體準確率的影響程度進行調參。
對於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的狀況一致,參數把模型向左推,可是模型的泛化偏差上升了。在這種狀況下,咱們顯然是不要把這個參數設置起來的,就讓它默認就行了。
不懈努力,繼續嘗試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同樣的結果,返回最小值而且模型總體的準確率下降了。
最後嘗試一下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_
調整完畢,總結出模型的最佳參數
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%,這對於調參來講實際上是一個很是巨大的進步。不過,泰坦尼克號數據的運行緩慢,你們量力量時間而行,能夠試試看用複雜度-泛化偏差方法(方差-誤差方法)來解讀一下這個調參結果和過程。
好了調參的步驟到這裏就結束了,感興趣的小夥伴們本身去敲一下代碼吧,學習機器學習最重要的就是要多動手練習一下代碼,多敲幾遍熟悉了就行了,加油。