機器學習sklearn(四十二):算法實例(十一)分類(五)RandomForestClassifier(二)實例:隨機森林在乳腺癌數據上的調參


  案例中,往往使用真實數據,為什么我們要使用sklearn自帶的數據呢?因為真實數據在隨機森林下的調參過程,往往非常緩慢。真實數據量大,維度高,在使用隨機森林之前需要一系列的處理,因此不太適合用來做直播中的案例演示。在本章,我為大家准備了kaggle上下載的辨別手寫數字的數據,有4W多條記錄700多個左右的特征,隨機森林在這個辨別手寫數字的數據上有非常好的表現,其調參案例也是非常經典,但是由於數據的維度太高,太過復雜,運行一次完整的網格搜索需要四五個小時,因此不太可能拿來給大家進行演示。我們上周的案例中用的泰坦尼克號數據,用來調參的話也是需要很長時間,因此我才選擇sklearn當中自帶的,結構相對清晰簡單的數據來為大家做這個案例。大家感興趣的話,可以進群去下載數據,也可以直接到kaggle上進行下載,數據集名稱是DigitRecognizer(https://www.kaggle.com/c/digit-recognizer)。那我們接下來,就用乳腺癌數據,來看看我們的調參代碼。
 
1. 導入需要的庫
from sklearn.datasets import load_breast_cancer
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import GridSearchCV
from sklearn.model_selection import cross_val_score
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
2. 導入數據集,探索數據
data = load_breast_cancer()
data
data.data.shape
data.target
#可以看到,乳腺癌數據集有569條記錄,30個特征,單看維度雖然不算太高,但是樣本量非常少。過擬合的情況可能存在
3. 進行一次簡單的建模,看看模型本身在數據集上的效果
rfc = RandomForestClassifier(n_estimators=100,random_state=90)
score_pre = cross_val_score(rfc,data.data,data.target,cv=10).mean()
score_pre
#這里可以看到,隨機森林在乳腺癌數據上的表現本就還不錯,在現實數據集上,基本上不可能什么都不調就看到95%以上的准確率
4. 隨機森林調整的第一步:無論如何先來調n_estimators
"""
在這里我們選擇學習曲線,可以使用網格搜索嗎?可以,但是只有學習曲線,才能看見趨勢
我個人的傾向是,要看見n_estimators在什么取值開始變得平穩,是否一直推動模型整體准確率的上升等信息
第一次的學習曲線,可以先用來幫助我們划定范圍,我們取每十個數作為一個階段,來觀察n_estimators的變化如何
引起模型整體准確率的變化
"""
#####【TIME WARNING: 30 seconds】#####
scorel = []
for i in range(0,200,10):
    rfc = RandomForestClassifier(n_estimators=i+1,
                                 n_jobs=-1,
                                 random_state=90)
    score = cross_val_score(rfc,data.data,data.target,cv=10).mean()
    scorel.append(score)
print(max(scorel),(scorel.index(max(scorel))*10)+1)
plt.figure(figsize=[20,5])
plt.plot(range(1,201,10),scorel)
plt.show()
#list.index([object])
#返回這個object在列表list中的索引

 

5. 在確定好的范圍內,進一步細化學習曲線
 
scorel = []
for i in range(35,45):
    rfc = RandomForestClassifier(n_estimators=i,
                                 n_jobs=-1,
                                 random_state=90)
    score = cross_val_score(rfc,data.data,data.target,cv=10).mean()
    scorel.append(score)
print(max(scorel),([*range(35,45)][scorel.index(max(scorel))]))
plt.figure(figsize=[20,5])
plt.plot(range(35,45),scorel)
plt.show()
  調整n_estimators的效果顯著,模型的准確率立刻上升了0.005。接下來就進入網格搜索,我們將使用網格搜索對參數一個個進行調整。為什么我們不同時調整多個參數呢?原因有兩個:1)同時調整多個參數會運行非常緩慢,在課堂上我們沒有這么多的時間。2)同時調整多個參數,會讓我們無法理解參數的組合是怎么得來的,所以即便網格搜索調出來的結果不好,我們也不知道從哪里去改。在這里,為了使用復雜度-泛化誤差方法(方差-偏差方法),我們對參數進行一個個地調整。
 
6. 為網格搜索做准備,書寫網格搜索的參數
"""
有一些參數是沒有參照的,很難說清一個范圍,這種情況下我們使用學習曲線,看趨勢
從曲線跑出的結果中選取一個更小的區間,再跑曲線
param_grid = {'n_estimators':np.arange(0, 200, 10)}
param_grid = {'max_depth':np.arange(1, 20, 1)}
    
param_grid = {'max_leaf_nodes':np.arange(25,50,1)}
 對於大型數據集,可以嘗試從1000來構建,先輸入1000,每100個葉子一個區間,再逐漸縮小范圍
有一些參數是可以找到一個范圍的,或者說我們知道他們的取值和隨着他們的取值,模型的整體准確率會如何變化,這
樣的參數我們就可以直接跑網格搜索
param_grid = {'criterion':['gini', 'entropy']}
param_grid = {'min_samples_split':np.arange(2, 2+20, 1)}
param_grid = {'min_samples_leaf':np.arange(1, 1+10, 1)}
 
param_grid = {'max_features':np.arange(5,30,1)} 
"""
7. 開始按照參數對模型整體准確率的影響程度進行調參,首先調整max_depth
#調整max_depth
param_grid = {'max_depth':np.arange(1, 20, 1)}
# 一般根據數據的大小來進行一個試探,乳腺癌數據很小,所以可以采用1~10,或者1~20這樣的試探
# 但對於像digit recognition那樣的大型數據來說,我們應該嘗試30~50層深度(或許還不足夠
#   更應該畫出學習曲線,來觀察深度對模型的影響
rfc = RandomForestClassifier(n_estimators=39
                             ,random_state=90
                           )
GS = GridSearchCV(rfc,param_grid,cv=10)
GS.fit(data.data,data.target)
GS.best_params_
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
param_grid = {'max_features':np.arange(5,30,1)} 
"""
max_features是唯一一個即能夠將模型往左(低方差高偏差)推,也能夠將模型往右(高方差低偏差)推的參數。我
們需要根據調參前,模型所在的位置(在泛化誤差最低點的左邊還是右邊)來決定我們要將max_features往哪邊調。
現在模型位於圖像左側,我們需要的是更高的復雜度,因此我們應該把max_features往更大的方向調整,可用的特征
越多,模型才會越復雜。max_features的默認最小值是sqrt(n_features),因此我們使用這個值作為調參范圍的
最小值。
"""
rfc = RandomForestClassifier(n_estimators=39
                             ,random_state=90
                           )
GS = GridSearchCV(rfc,param_grid,cv=10)
GS.fit(data.data,data.target)
GS.best_params_
GS.best_score_
網格搜索返回了max_features的最小值,可見max_features升高之后,模型的准確率降低了。這說明,我們把模型往右推,模型的泛化誤差增加了。前面用max_depth往左推,現在用max_features往右推,泛化誤差都增加,這說明模型本身已經處於泛化誤差最低點,已經達到了模型的預測上限,沒有參數可以左右的部分了。剩下的那些誤差,是噪聲決定的,已經沒有方差和偏差的舞台了。
 
如果是現實案例,我們到這一步其實就可以停下了,因為復雜度和泛化誤差的關系已經告訴我們,模型不能再進步了。調參和訓練模型都需要很長的時間,明知道模型不能進步了還繼續調整,不是一個有效率的做法。如果我們希望模型更進一步,我們會選擇更換算法,或者更換做數據預處理的方式。但是在課上,出於練習和探索的目的,我們繼續調整我們的參數,讓大家觀察一下模型的變化,看看我們預測得是否正確。
 
依然按照參數對模型整體准確率的影響程度進行調參。
 
9. 調整min_samples_leaf
#調整min_samples_leaf
param_grid={'min_samples_leaf':np.arange(1, 1+10, 1)}
#對於min_samples_split和min_samples_leaf,一般是從他們的最小值開始向上增加10或20
#面對高維度高樣本量數據,如果不放心,也可以直接+50,對於大型數據,可能需要200~300的范圍
#如果調整的時候發現准確率無論如何都上不來,那可以放心大膽調一個很大的數據,大力限制模型的復雜度
rfc = RandomForestClassifier(n_estimators=39
                             ,random_state=90
                           )
GS = GridSearchCV(rfc,param_grid,cv=10)
GS.fit(data.data,data.target)
GS.best_params_
GS.best_score_
可以看見,網格搜索返回了min_samples_leaf的最小值,並且模型整體的准確率還降低了,這和max_depth的情況一致,參數把模型向左推,但是模型的泛化誤差上升了。在這種情況下,我們顯然是不要把這個參數設置起來的,就讓它默認就好了。
 
10 不懈努力,繼續嘗試min_samples_split
#調整min_samples_split
param_grid={'min_samples_split':np.arange(2, 2+20, 1)}
rfc = RandomForestClassifier(n_estimators=39
                             ,random_state=90
                           )
GS = GridSearchCV(rfc,param_grid,cv=10)
GS.fit(data.data,data.target)
GS.best_params_
GS.best_score_
和min_samples_leaf一樣的結果,返回最小值並且模型整體的准確率降低了。
11. 最后嘗試一下criterion
#調整Criterion
param_grid = {'criterion':['gini', 'entropy']}
rfc = RandomForestClassifier(n_estimators=39
                             ,random_state=90
                           )
GS = GridSearchCV(rfc,param_grid,cv=10)
GS.fit(data.data,data.target)
GS.best_params_
GS.best_score_
12. 調整完畢,總結出模型的最佳參數
 
rfc = RandomForestClassifier(n_estimators=39,random_state=90)
score = cross_val_score(rfc,data.data,data.target,cv=10).mean()
score
score - score_pre
  在整個調參過程之中,我們首先調整了n_estimators(無論如何都請先走這一步),然后調整max_depth,通過max_depth產生的結果,來判斷模型位於復雜度-泛化誤差圖像的哪一邊,從而選擇我們應該調整的參數和調參的方向。如果感到困惑,也可以畫很多學習曲線來觀察參數會如何影響我們的准確率,選取學習曲線中單調的部分來放大研究(如同我們對n_estimators做的)。學習曲線的拐點也許就是我們一直在追求的,最佳復雜度對應的泛化誤差最低點(也是方差和偏差的平衡點)。
  網格搜索也可以一起調整多個參數,大家只要有時間,可以自己跑一下,看看網格搜索會給我們怎樣的結果,有時候,它的結果比我們的好,有時候,我們手動調整的結果會比較好。當然了,我們的乳腺癌數據集非常完美,所以只需要調n_estimators一個參數就達到了隨機森林在這個數據集上表現得極限。在我們上周使用的泰坦尼克號案例的數據中,我們使用同樣的方法調出了如下的參數組合。
rfc = RandomForestClassifier(n_estimators=68
                             ,random_state=90
                             ,criterion="gini"
                             ,min_samples_split=8
                             ,min_samples_leaf=1
                             ,max_depth=12
                             ,max_features=2
                             ,max_leaf_nodes=36
                             )
基於泰坦尼克號數據調整出來的參數,數據的處理過程請參考上一期的完整視頻。這個組合的准確率達到了83.915%,比單棵決策樹提升了大約7%,比調參前的隨機森林提升了2.02%,這對於調參來說其實是一個非常巨大的進步。不過,泰坦尼克號數據的運行緩慢,大家量力量時間而行,可以試試看用復雜度-泛化誤差方法(方差-偏差方法)來解讀一下這個調參結果和過程。
 
 
 
 
 
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM