(數據科學學習手札26)隨機森林分類器原理詳解&Python與R實現


一、簡介

  作為集成學習中非常著名的方法,隨機森林被譽為“代表集成學習技術水平的方法”,由於其簡單、容易實現、計算開銷小,使得它在現實任務中得到廣泛使用,因為其來源於決策樹和bagging,決策樹我在前面的一篇博客中已經詳細介紹,下面就來簡單介紹一下集成學習與Bagging;

 

二、集成學習

  集成學習(ensemble learning)是指通過構建並結合多個學習器來完成學習任務,有時也被稱為多分類器系統(multi-classifier system)等;

  集成學習的一般結構如下:

可以看出,集成學習的一般過程就是先產生一組“個體學習器”(individual learner),再使用某種策略將這些學習器結合起來。個體學習器通常由一個現有的學習算法從訓練數據產生,例如C4.5決策樹算法,BP神經網絡算法等,此時集成中只包含同種類型的個體學習器,譬如“決策樹集成”純由若干個決策樹學習器組成,這樣的集成是“同質”(homogeneous),同質集成中的個體學習器又稱作“基學習器”(base learner),相應的學習算法稱為“基學習算法”(base learning algorithm)。集成也可以包含不同類型的個體學習器,例如可以同時包含決策樹與神經網絡,這樣的集成就是“異質”的(heterogenous),異質集成中的個體學習器由不同的學習算法組成,這時不再有基學習算法;對應的,個體學習器也不再稱作基學習器,而是改稱為“組件學習器”(component learner)或直接成為個體學習器;

  集成學習通過將多個學習器進行結合,常可獲得比單一學習器更加顯著優越的泛化性能,尤其是對“弱學習器”(weak learner),因此集成學習的很多理論研究都是針對弱學習器來的,通過分別訓練各個個體學習器,預測時將待預測樣本輸入每個個體學習器中產出結果,最后使用加權和、最大投票法等方法將所有個體學習器的預測結果處理之后得到整個集成的最終結果,這就是集成學習的基本思想;

 

三、Bagging

  通過集成學習的思想,我們可以看出,想要得到泛化性能強的集成,則集成中的個體學習器應當盡可能相互獨立,但這在現實任務中幾乎無法實現,所以我們可以通過盡可能增大基學習器間的差異來達到類似的效果;一方面,我們希望盡可能增大基學習器間的差異:給定一個數據集,一種可能的做法是對訓練樣本進行采樣,分離出若干個子集,再從每個子集中訓練出一個基學習器,這樣我們訓練出的各個基學習器因為各自訓練集不同的原因就有希望取得比較大的差異;另一方面,為了獲得好的集成,我們希望個體學習器的性能不要太差,因為如果非要使得采樣出的每個自己彼此不相交,則由於每個子集樣本數量不足而無法進行有效學習,從而無法確保產生性能較好的個體學習器,為了解決這矛盾的問題,Bagging應運而生;

  Bagging是並行式集成學習方法最著名的代表,它基於自助采樣法(bootstrap sampling),對給定包含m個樣本的數據集,我們先隨機取出一個樣本放入采樣集中,再把該樣本放回初始數據集,即一次有放回的簡單隨機抽樣,這樣重復指定次數的抽樣,得到一個滿足要求的采樣集合,且樣本數據集中的樣本有的在該采樣集中多次出現,有的則從未出現過,我們可以將那些沒有在該采樣集出現過的樣本作為該采樣集對應訓練出的學習器的驗證集,來近似估計該個體學習器的泛化能力,這被稱作“包外估計”(out-of-bag estimate),令Dt表示第t個個體學習器對應的采樣集,令Hoob(x)表示該集成學習器對樣本x的包外預測,即僅考慮那些未使用x訓練的學習器在x上的預測表現,有:

則Bagging泛化誤差的包外估計為:

而且包外樣本還可以在一些特定的算法上實現較為實用的功能,例如當基學習器是決策樹時,可使用保外樣本來輔助剪枝,或用於估計決策樹中各結點的后驗概率以輔助對零訓練樣本節點的處理;當基學習器是神經網絡時,可以用包外樣本來輔助進行早停操作;

 

四、隨機森林

  隨機森林(Random Forest)是Bagging的一個擴展變體。其在以決策樹為基學習器構建Bagging集成的基礎上,進一步在決策樹的訓練過程中引入了隨機屬性選擇,即:傳統決策樹在選擇划分屬性時是在當前結點的屬性集合中(假設共有d個結點)基於信息純度准則等選擇一個最優屬性,而在隨機森林中,對基決策樹的每個結點,先從該結點的屬性集合中隨機選擇一個包含k個屬性的子集,再對該子集進行基於信息准則的划分屬性選擇;這里的k控制了隨機性的引入程度;若令k=d,則基決策樹的構建與傳統決策樹相同;若令k=1,則每次的屬性選擇純屬隨機,與信息准則無關;一般情況下,推薦k=log2d。

 

  隨機森林對Bagging只做了小小的改動,但是與Bagging中基學習器的“多樣性”僅通過樣本擾動(即改變采樣規則)不同,隨機森林中基學習器的多樣性不僅來自樣本擾動,還來自屬性擾動,這就使得最終集成的泛化性能可通過個體學習器之間差異度的增加而進一步提升;

  隨機森林的收斂性與Bagging類似,但隨機森林在基學習器數量較為可觀時性能會明顯提升,即隨着基學習器數量的增加,隨機森林會收斂到更低的泛化誤差;

 

五、Python實現

  我們使用sklearn.ensemble中的RandomForestClassifier()來進行隨機森林分類,其細節如下:

常用參數:

n_estimator:整數型,控制隨機森林算法中基決策樹的數量,默認為10,我建議取一個100-1000之間的奇數;

criterion:字符型,用來指定做屬性划分時使用的評價准則,'gini'表示基尼系數,也就是CART樹,'entropy'表示信息增益;

max_features:用來控制每個結點划分時從當前樣本的屬性集合中隨機抽取的屬性個數,即控制了隨機性的引入程度,默認為'auto',有以下幾種選擇:

  1.int型時,則該傳入參數即作為max_features;

  2.float型時,將 傳入數值*n_features 作為max_features;

  3.字符串時,若為'auto',max_features=sqrt(n_features);'sqrt'時, 同'auto';'log2'時,max_features=log2(n_features);

  4.None時,max_features=n_features;

max_depth:控制每棵樹所有預測路徑的長度上限(即從根結點出發經歷的划分屬性的個數),建議訓練時該參數從小逐漸調大;默認為None,此時每棵樹只有等到所有的葉結點中都只存在一種類別的樣本或結點中樣本數小於min_samples_split時化成葉結點時該預測路徑才停止生長;

min_samples_split:該參數控制當結點中樣本數量小於某個整數k時將某個結點標記為葉結點(即停止該預測路徑的生長),傳入參數即控制k,當傳入參數為整數時,該參數即為k;當傳入參數屬於0.0~1.0之間時,k=傳入參數*n_samples;默認值為2;

max_leaf_nodes:控制每棵樹的最大葉結點數量,默認為None,即無限制;

min_impurity_decrease:控制過擬合的一種措施,傳入一個浮點型的數,則在每棵樹的生長過程中,若下一個節點中的信息純度與上一個結點中的節點純度差距小於這個值,則這一次划分被剪去;

booststrap:bool型變量,控制是否采取自助法來划分每棵樹的訓練數據(即每棵樹的訓練數據間是否存在相交的可能),默認為True;

oob_score:bool型變量,控制是否用包外誤差來近似學習器的泛化誤差;

n_jobs:控制並行運算時的核心數,默認為單核即1,特別的,設置為-1時開啟所有核心;

random_rate:設置隨機數種子,目的是控制算法中隨機的部分,默認為None,即每次運行都是隨機地(偽隨機);

class_weight:用於處理類別不平衡問題,即為每一個類別賦權,默認為None,即每個類別權重都為1;'balanced'則自動根據樣本集中的類別比例為算法賦權;

函數輸出項:

estimators_:包含所有訓練好的基決策樹細節的列表;

classes:顯示所有類別;

n_classes_:顯示類別總數;

n_features_:顯示特征數量(訓練之后才有這個輸出項);

feature_importances_:顯示訓練中所有特征的重要程度,越大越重要;

oob_score_:學習器的包外估計得分;

下面我們以sklearn.datasets自帶的威斯康辛州乳腺癌數據作為演示數據,具體過程如下:

from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import f1_score as f1
from sklearn.metrics import confusion_matrix as con
from sklearn import datasets


###載入威斯康辛州乳腺癌數據
X,y = datasets.load_breast_cancer(return_X_y=True)

###分割訓練集與測試集
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.3)

###初始化隨機森林分類器,這里為類別做平衡處理
clf = RandomForestClassifier(class_weight='balanced',random_state=1)

###返回由訓練集訓練成的模型對驗證集預測的結果
result = clf.fit(X_train,y_train).predict(X_test)

###打印混淆矩陣
print('\n'+'混淆矩陣:')
print(con(y_test,result))

###打印F1得分
print('\n'+'F1 Score:')
print(f1(y_test,result))

###打印測試准確率
print('\n'+'Accuracy:')
print(clf.score(X_test,y_test))

運行結果如下:

可以看出,隨機森林的性能十分優越。

 

六、R實現

  在R語言中我們使用randomForest包中的randomForest()函數來進行隨機森林模型的訓練,其主要參數如下:

formula:一種 因變量~自變量 的公式格式;

data:用於指定訓練數據所在的數據框;

xtest:randomForest提供了一種很舒服的(我竊認為)將訓練與驗證一步到位的體制,這里xtest傳入的就是驗證集中的自變量;

ytest:對應xtest的驗證集的label列,缺省時則xtest視為無標簽的待預測數據,這時可以使用test$predicted來調出對應的預測值(實在是太舒服了);

ntree:基決策樹的數量,默認是500(R相當實在),我建議設定為一個大小比較適合的奇數;

classwt:用於處理類別不平衡問題,即傳入一個包含因變量各類別比例的向量;

nodesize:生成葉結點的最小樣本數,即當某個結點中樣本數量小於這個值時自動將該結點標記為葉結點並計算輸出概率,好處是可以盡量避免生長出太過於龐大的樹,也就減少了過擬合的可能,也在一定程度上縮短了訓練時間;

maxnodes:每顆基決策樹允許產生的最大的葉結點數量,缺省時則每棵樹無限制生長;

importance:邏輯型變量,控制是否計算每個變量的重要程度;

proxi:邏輯型變量,控制是否計算每顆基決策樹的復雜度;

函數輸出項:

call:訓練好的隨機森林模型的預設參數情況;

type:輸出模型對應的問題類型,有'regression','classification','unsupervised';

importance:輸出所有特征在模型中的貢獻程度;

ntree:輸出基決策樹的顆數;

test$predicted:輸出在ytest缺省,xtest給出的情況下,其對應的預測值;

test$confusion:輸出在xtest,ytest均給出的條件下,xtest的預測值與ytest代表的正確標記之間的混淆矩陣;

test$votes:輸出隨機森林模型中每一棵樹對xtest每一個樣本的投票情況;

下面我們以鳶尾花數據為例,進行演示,具體過程如下:

 

> rm(list=ls())
> library(randomForest)
> 
> #load data
> data(iris)
> 
> #split data
> sam = sample(1:150,120)
> train = iris[sam,]
> test = iris[-sam,]
> 
> #訓練隨機森林分類器
> rf = randomForest(Species~.,data=train,
+                   classwt=table(train$Species)/dim(train)[1],
+                   ntree=11,
+                   xtest=test[,1:4],
+                   importance=T,
+                   proximity=T)
> 
> #打印混淆矩陣
> rf$test$confusion
NULL
> 
> #打印正確率
> sum(diag(prop.table(table(test$Species,rf$test$predicted))))
[1] 1
> 
> #打印特征的重要性程度
> importance(rf,type=2)
             MeanDecreaseGini
Sepal.Length         8.149513
Sepal.Width          1.485798
Petal.Length        38.623601
Petal.Width         31.085027
> 
> #可視化特征的重要性程度
> varImpPlot(rf)

 

特征重要程度可視化:

上圖每個點表示將對應的特征移除后平均減少了正確率,所以點在圖中位置越高就越重要;

輸出每個樣本接受基決策樹投票的具體情況:

> #vote results of base decision tree
> rf$test$votes
       setosa versicolor virginica
2   1.0000000 0.00000000 0.0000000
8   1.0000000 0.00000000 0.0000000
13  1.0000000 0.00000000 0.0000000
14  1.0000000 0.00000000 0.0000000
15  0.9090909 0.09090909 0.0000000
18  1.0000000 0.00000000 0.0000000
20  1.0000000 0.00000000 0.0000000
25  1.0000000 0.00000000 0.0000000
26  1.0000000 0.00000000 0.0000000
27  1.0000000 0.00000000 0.0000000
32  1.0000000 0.00000000 0.0000000
36  1.0000000 0.00000000 0.0000000
37  1.0000000 0.00000000 0.0000000
39  1.0000000 0.00000000 0.0000000
61  0.0000000 1.00000000 0.0000000
62  0.0000000 1.00000000 0.0000000
87  0.0000000 1.00000000 0.0000000
91  0.0000000 1.00000000 0.0000000
96  0.0000000 1.00000000 0.0000000
97  0.0000000 1.00000000 0.0000000
104 0.0000000 0.00000000 1.0000000
108 0.0000000 0.00000000 1.0000000
110 0.0000000 0.00000000 1.0000000
111 0.0000000 0.00000000 1.0000000
113 0.0000000 0.00000000 1.0000000
122 0.0000000 0.09090909 0.9090909
126 0.0000000 0.00000000 1.0000000
128 0.0000000 0.00000000 1.0000000
140 0.0000000 0.00000000 1.0000000
143 0.0000000 0.09090909 0.9090909
attr(,"class")
[1] "matrix" "votes" 

 

  以上就是關於隨機森林的基本內容,本篇今后會陸續補充更深層次的知識,如有筆誤,望指出。

  


免責聲明!

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



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