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.2 n_estimators
這是森林中樹木的數量,即基評估器的數量。這個參數對隨機森林模型的精確性影響是單調的,n_estimators越大,模型的效果往往越好。但是相應的,任何模型都有決策邊界,n_estimators達到一定的程度之后,隨機森林的精確性往往不在上升或開始波動,並且,n_estimators越大,需要的計算量和內存也越大,訓練的時間也會越來越長。對於這個參數,我們是渴望在訓練難度和模型效果之間取得平衡。
n_estimators的默認值在現有版本的sklearn中是10,但是在即將更新的0.22版本中,這個默認值會被修正為100。這個修正顯示出了使用者的調參傾向:要更大的n_estimators。
來建立一片森林吧
樹模型的優點是簡單易懂,可視化之后的樹人人都能夠看懂,可惜隨機森林是無法被可視化的。所以為了更加直觀地讓大家體會隨機森林的效果,我們來進行一個隨機森林和單個決策樹效益的對比。我們依然使用紅酒數據集。
1. 導入我們需要的包
%matplotlib inline from sklearn.tree import DecisionTreeClassifier from sklearn.ensemble import RandomForestClassifier from sklearn.datasets import load_wine
2. 導入需要的數據集
wine = load_wine()
wine.data
wine.target
3. 復習: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_c = clf.score(Xtest,Ytest) score_r = rfc.score(Xtest,Ytest) print("Single Tree:{}".format(score_c) ,"Random Forest:{}".format(score_r) )
4. 畫出隨機森林和決策樹在一組交叉驗證下的效果對比
#目的是帶大家復習一下交叉驗證 #交叉驗證:是數據集划分為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%的預測正確率。