機器學習sklearn(三十九):演算法例項(八)分類(四)隨機森林分類器 RandomForestRegressor
阿新 • • 發佈:2021-06-23
class sklearn.ensemble.RandomForestRegressor(n_estimators=’warn’, criterion=’mse’, max_depth=None,min_samples_split=2, min_samples_leaf=1, min_weight_fraction_leaf=0.0, max_features=’auto’,max_leaf_nodes=None, min_impurity_decrease=0.0, min_impurity_split=None, bootstrap=True, oob_score=False,n_jobs=None, random_state=None, verbose=0, warm_start=False)
所有的引數,屬性與介面,全部和隨機森林分類器一致。僅有的不同就是迴歸樹與分類樹的不同,不純度的指標,引數Criterion不一致。
樹模型的優點是簡單易懂,視覺化之後的樹人人都能夠看懂,可惜隨機森林是無法被視覺化的。所以為了更加直觀地讓大家體會隨機森林的效果,我們來進行一個隨機森林和單個決策樹效益的對比。我們依然使用紅酒資料集。
1. 匯入我們需要的包
1 重要引數
1.1 控制基評估器的引數 這些引數在隨機森林中的含義,和我們在上決策樹時說明的內容一模一樣,單個決策樹的準確率越高,隨機森林的準確率也會越高,因為裝袋法是依賴於平均值或者少數服從多數原則來決定整合的結果的。 1.2 n_estimators 這是森林中樹木的數量,即基評估器的數量。這個引數對隨機森林模型的精確性影響是單調的,n_estimators越大,模型的效果往往越好。但是相應的,任何模型都有決策邊界,n_estimators達到一定的程度之後,隨機森林的精確性往往不在上升或開始波動,並且,n_estimators越大,需要的計算量和記憶體也越大,訓練的時間也會越來越長。對於這個引數,我們是渴望在訓練難度和模型效果之間取得平衡。 n_estimators的預設值在現有版本的sklearn中是10,但是在即將更新的0.22版本中,這個預設值會被修正為100。這個修正顯示出了使用者的調參傾向:要更大的n_estimators。 來建立一片森林吧%matplotlib inline from sklearn.tree import DecisionTreeClassifier from sklearn.ensemble import RandomForestClassifier from sklearn.datasets import load_wine2. 匯入需要的資料集
wine = load_wine() wine.data wine.target3. 複習:sklearn建模的基本流程
from sklearn.model_selection import train_test_split Xtrain, Xtest, Ytrain, Ytest = train_test_split(wine.data,wine.target,test_size=0.3) clf = DecisionTreeClassifier(random_state=0) rfc = RandomForestClassifier(random_state=0) clf = clf.fit(Xtrain,Ytrain) rfc = rfc.fit(Xtrain,Ytrain) score_c4. 畫出隨機森林和決策樹在一組交叉驗證下的效果對比= clf.score(Xtest,Ytest) score_r = rfc.score(Xtest,Ytest) print("Single Tree:{}".format(score_c) ,"Random Forest:{}".format(score_r) )
#目的是帶大家複習一下交叉驗證 #交叉驗證:是資料集劃分為n分,依次取每一份做測試集,每n-1份做訓練集,多次訓練模型以觀測模型穩定性的方法 from sklearn.model_selection import cross_val_score import matplotlib.pyplot as plt rfc = RandomForestClassifier(n_estimators=25) rfc_s = cross_val_score(rfc,wine.data,wine.target,cv=10) clf = DecisionTreeClassifier() clf_s = cross_val_score(clf,wine.data,wine.target,cv=10) plt.plot(range(1,11),rfc_s,label = "RandomForest") plt.plot(range(1,11),clf_s,label = "Decision Tree") plt.legend() plt.show() #====================一種更加有趣也更簡單的寫法===================# """ label = "RandomForest" for model in [RandomForestClassifier(n_estimators=25),DecisionTreeClassifier()]: score = cross_val_score(model,wine.data,wine.target,cv=10) print("{}:".format(label)),print(score.mean()) plt.plot(range(1,11),score,label = label) plt.legend() label = "DecisionTree" """5. 畫出隨機森林和決策樹在十組交叉驗證下的效果對比
rfc_l = [] clf_l = [] for i in range(10): rfc = RandomForestClassifier(n_estimators=25) rfc_s = cross_val_score(rfc,wine.data,wine.target,cv=10).mean() rfc_l.append(rfc_s) clf = DecisionTreeClassifier() clf_s = cross_val_score(clf,wine.data,wine.target,cv=10).mean() clf_l.append(clf_s) plt.plot(range(1,11),rfc_l,label = "Random Forest") plt.plot(range(1,11),clf_l,label = "Decision Tree") plt.legend() plt.show() #是否有注意到,單個決策樹的波動軌跡和隨機森林一致? #再次驗證了我們之前提到的,單個決策樹的準確率越高,隨機森林的準確率也會越高6. n_estimators的學習曲線
#####【TIME WARNING: 2mins 30 seconds】##### superpa = [] for i in range(200): rfc = RandomForestClassifier(n_estimators=i+1,n_jobs=-1) rfc_s = cross_val_score(rfc,wine.data,wine.target,cv=10).mean() superpa.append(rfc_s) print(max(superpa),superpa.index(max(superpa))) plt.figure(figsize=[20,5]) plt.plot(range(1,201),superpa) plt.show()1.3 random_state 隨機森林的本質是一種裝袋整合演算法(bagging),裝袋整合演算法是對基評估器的預測結果進行平均或用多數表決原則來決定整合評估器的結果。在剛才的紅酒例子中,我們建立了25棵樹,對任何一個樣本而言,平均或多數表決原則下,當且僅當有13棵以上的樹判斷錯誤的時候,隨機森林才會判斷錯誤。單獨一棵決策樹對紅酒資料集的分類準確率在0.85上下浮動,假設一棵樹判斷錯誤的可能性為0.2(ε),那20棵樹以上都判斷錯誤的可能性是: 其中,i是判斷錯誤的次數,也是判錯的樹的數量,ε是一棵樹判斷錯誤的概率,(1-ε)是判斷正確的概率,共判對25-i次。採用組合,是因為25棵樹中,有任意i棵都判斷錯誤。
import numpy as np from scipy.special import comb np.array([comb(25,i)*(0.2**i)*((1-0.2)**(25-i)) for i in range(13,26)]).sum()可見,判斷錯誤的機率非常小,這讓隨機森林在紅酒資料集上的表現遠遠好於單棵決策樹。 那現在就有一個問題了:我們說袋裝法服從多數表決原則或對基分類器結果求平均,這即是說,我們預設森林中的每棵樹應該是不同的,並且會返回不同的結果。設想一下,如果隨機森林裡所有的樹的判斷結果都一致(全判斷對或全判斷錯),那隨機森林無論應用何種整合原則來求結果,都應該無法比單棵決策樹取得更好的效果才對。但我們使用了一樣的類DecisionTreeClassififier,一樣的引數,一樣的訓練集和測試集,為什麼隨機森林裡的眾多樹會有不同的判斷結果? 問到這個問題,很多小夥伴可能就會想到了:sklearn中的分類樹DecisionTreeClassififier自帶隨機性,所以隨機森林中的樹天生就都是不一樣的。我們在講解分類樹時曾提到,決策樹從最重要的特徵中隨機選擇出一個特徵來進行分枝,因此每次生成的決策樹都不一樣,這個功能由引數random_state控制。隨機森林中其實也有random_state,用法和分類樹中相似,只不過在分類樹中,一個random_state只控制生成一棵樹,而隨機森林中的random_state控制的是生成森林的模式,而非讓一個森林中只有一棵樹。
rfc = RandomForestClassifier(n_estimators=20,random_state=2) rfc = rfc.fit(Xtrain, Ytrain) #隨機森林的重要屬性之一:estimators,檢視森林中樹的狀況 rfc.estimators_[0].random_state for i in range(len(rfc.estimators_)): print(rfc.estimators_[i].random_state)我們可以觀察到,當random_state固定時,隨機森林中生成是一組固定的樹,但每棵樹依然是不一致的,這是用”隨機挑選特徵進行分枝“的方法得到的隨機性。並且我們可以證明,當這種隨機性越大的時候,袋裝法的效果一般會越來越好。用袋裝法整合時,基分類器應當是相互獨立的,是不相同的。 但這種做法的侷限性是很強的,當我們需要成千上萬棵樹的時候,資料不一定能夠提供成千上萬的特徵來讓我們構築儘量多儘量不同的樹。因此,除了random_state。我們還需要其他的隨機性。
1.4 bootstrap & oob_score
要讓基分類器儘量都不一樣,一種很容易理解的方法是使用不同的訓練集來進行訓練,而袋裝法正是通過有放回的隨機抽樣技術來形成不同的訓練資料,bootstrap就是用來控制抽樣技術的引數。 在一個含有n個樣本的原始訓練集中,我們進行隨機取樣,每次取樣一個樣本,並在抽取下一個樣本之前將該樣本放回原始訓練集,也就是說下次取樣時這個樣本依然可能被採集到,這樣採集n次,最終得到一個和原始訓練集一樣大的,n個樣本組成的自助集。由於是隨機取樣,這樣每次的自助集和原始資料集不同,和其他的取樣集也是不同的。這樣我們就可以自由創造取之不盡用之不竭,並且互不相同的自助集,用這些自助集來訓練我們的基分類器,我們的基分類器自然也就各不相同了。 bootstrap引數預設True,代表採用這種有放回的隨機抽樣技術。通常,這個引數不會被我們設定為False。 然而有放回抽樣也會有自己的問題。由於是有放回,一些樣本可能在同一個自助集中出現多次,而其他一些卻可能被忽略,一般來說,自助集大約平均會包含63%的原始資料。因為每一個樣本被抽到某個自助集中的概率為: 當n足夠大時,這個概率收斂於1-(1/e),約等於0.632。因此,會有約37%的訓練資料被浪費掉,沒有參與建模,這些資料被稱為袋外資料(out of bag data,簡寫為oob)。除了我們最開始就劃分好的測試集之外,這些資料也可以被用來作為整合演算法的測試集。也就是說,在使用隨機森林時,我們可以不劃分測試集和訓練集,只需要用袋外資料來測試我們的模型即可。當然,這也不是絕對的,當n和n_estimators都不夠大的時候,很可能就沒有資料掉落在袋外,自然也就無法使用oob資料來測試模型了。 如果希望用袋外資料來測試,則需要在例項化時就將oob_score這個引數調整為True,訓練完畢之後,我們可以用隨機森林的另一個重要屬性:oob_score_來檢視我們的在袋外資料上測試的結果:#無需劃分訓練集和測試集 rfc = RandomForestClassifier(n_estimators=25,oob_score=True) rfc = rfc.fit(wine.data,wine.target) #重要屬性oob_score_ rfc.oob_score_
2 重要屬性和介面
至此,我們已經講完了所有隨機森林中的重要引數,為大家複習了一下決策樹的引數,並通過n_estimators,random_state,boostrap和oob_score這四個引數幫助大家瞭解了袋裝法的基本流程和重要概念。同時,我們還介紹了.estimators_ 和 .oob_score_ 這兩個重要屬性。除了這兩個屬性之外,作為樹模型的整合演算法,隨機森林自然也有.feature_importances_這個屬性。 隨機森林的介面與決策樹完全一致,因此依然有四個常用介面:apply, fifit, predict和score。除此之外,還需要注意隨機森林的predict_proba介面,這個介面返回每個測試樣本對應的被分到每一類標籤的概率,標籤有幾個分類就返回幾個概率。如果是二分類問題,則predict_proba返回的數值大於0.5的,被分為1,小於0.5的,被分為0。傳統的隨機森林是利用袋裝法中的規則,平均或少數服從多數來決定整合的結果,而sklearn中的隨機森林是平均每個樣本對應的predict_proba返回的概率,得到一個平均概率,從而決定測試樣本的分類。#大家可以分別取嘗試一下這些屬性和介面 rfc = RandomForestClassifier(n_estimators=25) rfc = rfc.fit(Xtrain, Ytrain) rfc.score(Xtest,Ytest) rfc.feature_importances_ rfc.apply(Xtest) rfc.predict(Xtest) rfc.predict_proba(Xtest)掌握了上面的知識,基本上要實現隨機森林分類已經是沒問題了。從紅酒資料集的表現上來看,隨機森林的效用比單純的決策樹要強上不少,大家可以自己更換其他資料來試試看(比如上週完整課案例中的泰坦尼克號資料)。 Bonus:Bagging的另一個必要條件 之前我們說過,在使用袋裝法時要求基評估器要儘量獨立。其實,袋裝法還有另一個必要條件:基分類器的判斷準確率至少要超過隨機分類器,即時說,基分類器的判斷準確率至少要超過50%。之前我們已經展示過隨機森林的準確率公式,基於這個公式,我們畫出了基分類器的誤差率ε和隨機森林的誤差率之間的影象。大家可以自己執行一下這段程式碼,看看影象呈什麼樣的分佈。
import numpy as np x = np.linspace(0,1,20) y = [] for epsilon in np.linspace(0,1,20): E = np.array([comb(25,i)*(epsilon**i)*((1-epsilon)**(25-i)) for i in range(13,26)]).sum() y.append(E) plt.plot(x,y,"o-",label="when estimators are different") plt.plot(x,x,"--",color="red",label="if all estimators are same") plt.xlabel("individual estimator's error") plt.ylabel("RandomForest's error") plt.legend() plt.show()可以從影象上看出,當基分類器的誤差率小於0.5,即準確率大於0.5時,整合的效果是比基分類器要好的。相反,當基分類器的誤差率大於0.5,袋裝的整合演算法就失效了。所以在使用隨機森林之前,一定要檢查,用來組成隨機森林的分類樹們是否都有至少50%的預測正確率。