1. 程式人生 > >R語言︱決策樹族——隨機森林演算法

R語言︱決策樹族——隨機森林演算法

筆者寄語:有一篇《有監督學習選擇深度學習還是隨機森林或支援向量機?》(作者BioSebastianRaschka)中提到,在日常機器學習工作或學習中,當我們遇到有監督學習相關問題時,不妨考慮下先用簡單的假設空間(簡單模型集合),例如線性模型邏輯迴歸。若效果不好,也即並沒達到你的預期或評判效果基準時,再進行下換其他更復雜模型來實驗。

 

——————————————————————————————————————————————

 

一、隨機森林理論介紹

 

1.1 優缺點

 

 

優點。

(1)不必擔心過度擬合;

(2)適用於資料集中存在大量未知特徵;

(3)能夠估計哪個特徵在分類中更重要;

(4)具有很好的抗噪聲能力;

(5)演算法容易理解;

(6)可以並行處理。

缺點。

(1)對小量資料集和低維資料集的分類不一定可以得到很好的效果。

(2)執行速度雖然比Boosting等快,但是比單個的決策樹慢很多。

(3)可能會出現一些差異度非常小的樹,淹沒了一些正確的決策。

 

1.2 生成步驟介紹

 

 

 

1、從原始訓練資料集中,應用bootstrap方法有放回地隨機抽取k個新的自助樣本集,並由此構建k棵分類迴歸樹,每次未被抽到的樣本組成了K個袋外資料(out-of-bag,BBB)。

2、設有n 個特徵,則在每一棵樹的每個節點處隨機抽取mtry 個特徵,通過計算每個特徵蘊含的資訊量,特徵中選擇一個最具有分類能力的特徵進行節點分裂。

3、每棵樹最大限度地生長, 不做任何剪裁

4、將生成的多棵樹組成隨機森林, 用隨機森林對新的資料進行分類, 分類結果按樹分類器投票多少而定。

 

1.3 隨機森林與SVM的比較

 

(1)不需要調節過多的引數,因為隨機森林只需要調節樹的數量,而且樹的數量一般是越多越好,而其他機器學習演算法,比如SVM,有非常多超引數需要調整,如選擇最合適的核函式,正則懲罰等。

(2)分類較為簡單、直接。隨機深林和支援向量機都是非引數模型(複雜度隨著訓練模型樣本的增加而增大)。相較於一般線性模型,就計算消耗來看,訓練非引數模型因此更為耗時耗力。分類樹越多,需要更耗時來構建隨機森林模型。同樣,我們訓練出來的支援向量機有很多支援向量,最壞情況為,我們訓練集有多少例項,就有多少支援向量。雖然,我們可以使用多類支援向量機,但傳統多類分類問題的執行一般是one-vs-all(所謂one-vs-all 就是將binary分類的方法應用到多類分類中。比如我想分成K類,那麼就將其中一類作為positive),因此我們還是需要為每個類訓練一個支援向量機。相反,決策樹與隨機深林則可以毫無壓力解決多類問題。

(3)比較容易入手實踐。隨機森林在訓練模型上要更為簡單。你很容易可以得到一個又好且具魯棒性的模型。隨機森林模型的複雜度與訓練樣本和樹成正比。支援向量機則需要我們在調參方面做些工作,除此之外,計算成本會隨著類增加呈線性增長。

(4)小資料上,SVM優異,而隨機森林對資料需求較大。就經驗來說,我更願意認為支援向量機在存在較少極值的小資料集上具有優勢。隨機森林則需要更多資料但一般可以得到非常好的且具有魯棒性的模型。

 

 

1.5 隨機森林與深度學習的比較

 

深度學習需要比隨機森林更大的模型來擬合模型,往往,深度學習演算法需要耗時更大,相比於諸如隨機森林和支援向量機那樣的現成分類器,安裝配置好一個神經網路模型來使用深度學習演算法的過程則更為乏味。

但不可否認,深度學習在更為複雜問題上,如圖片分類,自然語言處理,語音識別方面更具優勢。

另外一個優勢為你不需要太關注特徵工程相關工作。實際上,至於如何選擇分類器取決於你的資料量和問題的一般複雜性(和你要求的效果)。這也是你作為機器學習從業者逐步會獲得的經驗。

可參考論文《An Empirical Comparison of Supervised Learning Algorithms》。

 

 

1.6 隨機森林與決策樹之間的區別

 

模型克服了單棵決策樹易過擬合的缺點,模型效果在準確性和穩定性方面都有顯著提升。

 

決策樹+bagging=隨機森林

 

 

 

1.7 隨機森林不會發生過擬合的原因

 

在建立每一棵決策樹的過程中,有兩點需要注意-取樣與完全分裂。首先是兩個隨機取樣的過程,random forest對輸入的資料要進行行、列的取樣。對於行取樣,採用有放回的方式,也就是在取樣得到的樣本集合中,可能有重複的樣本。

假設輸入樣本為N個,那麼取樣的樣本也為N個。這樣使得在訓練的時候,每一棵樹的輸入樣本都不是全部的樣本,使得相對不容易出現over-fitting。

 

然後進行列取樣,從M個feature中,選擇m個(m << M)。之後就是對取樣之後的資料使用完全分裂的方式建立出決策樹,這樣決策樹的某一個葉子節點要麼是無法繼續分裂的,要麼裡面的所有樣本的都是指向的同一個分類。一般很多的決策樹演算法都一個重要的步驟-剪枝,但是這裡不這樣幹,由於之前的兩個隨機取樣的過程保證了隨機性,所以就算不剪枝,也不會出現over-fitting。 按這種演算法得到的隨機森林中的每一棵都是很弱的,但是大家組合起來就很厲害了。

 

可以這樣比喻隨機森林演算法:每一棵決策樹就是一個精通於某一個窄領域的專家(因為我們從M個feature中選擇m讓每一棵決策樹進行學習),這樣在隨機森林中就有了很多個精通不同領域的專家,對一個新的問題(新的輸入資料),可以用不同的角度去看待它,最終由各個專家,投票得到結果。

 

 

1.8 隨機森林與梯度提升樹(GBDT)區別

 

隨機森林:決策樹+bagging=隨機森林

梯度提升樹:決策樹Boosting=GBDT

 

兩者區別在於bagging boosting之間的區別,可見:

 

 

bagging

boosting

取樣方式

bagging採用均勻取樣

boosting根據錯誤率來取樣

精度、準確性

相比之,較低

訓練集選擇

隨機的,各輪訓練集之前互相獨立

各輪訓練集的選擇與前面各輪的學習結果相關

預測函式權重

各個預測函式沒有權重

boost有權重

函式生成順序

並行生成

順序生成

應用

象神經網路這樣極為消耗時間的演算法,bagging可通過並行節省大量的時間開銷

baging和boosting都可以有效地提高分類的準確性

baging和boosting都可以有效地提高分類的準確性

一些模型中會造成模型的退化(過擬合)

boosting思想的一種改進型adaboost方法在郵件過濾,文字分類中有很好的效能

 

隨機森林

梯度提升樹

 

 

 

——————————————————————————————————————————————

 

 

二、隨機森林重要性度量指標——重要性評分、Gini指數

 

(1)重要性評分

 

 

定義為袋外資料自變數值發生輕微擾動後的分類正確率與擾動前分類正確率的平均減少量。

(1):對於每棵決策樹,利用袋外資料進行預測,將袋外資料的預測誤差將記錄下來。其每棵樹的誤差是:vote1,vote2····,voteb;

(2):隨機變換每個預測變數,從而形成新的袋外資料,再利用袋外資料進行驗證,其每個變數的誤差是:vote11,vote12,···,vote1b。

(3):對於某預測變數來說,計算其重要性是變換後的預測誤差與原來相比的差的均值。

r語言中程式碼:

 

[plain] view plain copy

  1. rf <- randomForest(Species ~ ., data=a, ntree=100, proximity=TRUE,importance=TRUE)  

 

 

 

(2)gini指數

 

 

 

gini指數表示節點的純度,gini指數越大純度越低。gini值平均降低量表示所有樹的變數分割節點平均減小的不純度。對於變數重要度衡量,步驟如同前面介紹,將變數資料打亂,gini指數變化的均值作為變數的重要程度度量。

 

gini(T)=1−∑j=1np2j

 

 

(3)重要性繪圖函式——varImpPlot(rf)函式

 

 

 

 

——————————————————————————————————————————————

 

 

三、隨機森林模型R語言實踐

 

3.1 隨機森林模型幾點注意

 

模型中關於分類任務以及迴歸預測任務的區別:

隨機森林模型,分類和迴歸預測的操作不同之處在於判斷因變數的型別,如果因變數是因子則執行分類任務,如果因變數是連續性變數,則執行迴歸預測任務。

 

模型中關於資料結構的要求:

`randomForest`函式要求為資料框或者矩陣,需要原來的資料框調整為以每個詞作為列名稱(變數)的資料框。在文字挖掘的過程中,需要把詞頻(橫向,long型資料)轉化為變數(wide型縱向資料),可以用reshape2、data.table包來中dcast來實現。具體實戰見部落格:R語言︱監督演算法式的情感分析筆記的4.1節。

 

 

隨機森林的兩個引數:

 

候選特徵數K
K越大,單棵樹的效果會提升,但樹之間相關性也會增強
決策樹數量M
M越大,模型效果會有提升,但計算量會變大

 

 

R中與決策樹有關的Package:


單棵決策樹:rpart/tree/C50
隨機森林:randomforest/ranger
梯度提升樹:gbm/xgboost
樹的視覺化:rpart.plot

 

3.2 模型擬合

 

本文以R語言中自帶的資料集iris為例,以setosa為因變數,其他作為自變數進行模型擬合,由於setosa本身就是因子型,所以不用轉換形式。

 

 

[plain] view plain copy

  1. > data <- iris  
  2. > library(randomForest)  
  3. > system.time(Randommodel <- randomForest(Species ~ ., data=data,importance = TRUE, proximity = FALSE, ntree = 100))  
  4. 使用者 系統 流逝   
  5.    0    0    0   
  6. > print(Randommodel)  
  7.   
  8. Call:  
  9.  randomForest(formula = Species ~ ., data = data, importance = TRUE,      proximity = FALSE, ntree = 100)   
  10.                Type of random forest: classification  
  11.                      Number of trees: 100  
  12. No. of variables tried at each split: 2  
  13.   
  14.         OOB estimate of  error rate: 3.33%  
  15. Confusion matrix:  
  16.            setosa versicolor virginica class.error  
  17. setosa         50          0         0        0.00  
  18. versicolor      0         47         3        0.06  
  19. virginica       0          2        48        0.04  

 

 

 

程式碼解讀:randomForset,執行建模,x引數設定自變數資料集,y引數設定因變數資料列,importance設定是否輸出因變數在模型中的重要性,如果移除某個變數,模型方差增加的比例是它判斷變數重要性的標準之一,proximity引數用於設定是否計算模型的臨近矩陣,ntree用於設定隨機森林的樹數(後面單獨討論),最後一句輸出模型在訓練集上的效果。

prInt輸出模型在訓練集上的效果,可以看出錯誤率為3.33%,維持在比較低的水平。

 

3.3 隨機森林模型重要性檢測

 

 

[plain] view plain copy

  1. > importance(Randommodel,type=1)  #重要性評分  
  2.              MeanDecreaseAccuracy  
  3. Sepal.Length             4.720094  
  4. Sepal.Width              1.405924  
  5. Petal.Length            16.222059  
  6. Petal.Width             13.895115  
  7. > importance(Randommodel,type=2)  #Gini指數  
  8.              MeanDecreaseGini  
  9. Sepal.Length         9.484106  
  10. Sepal.Width          1.930289  
  11. Petal.Length        45.873386  
  12. Petal.Width         41.894352  
  13. > varImpPlot(Randommodel)         #視覺化  

 

 

 

利用iris資料,可以看到這四個變數的重要性排序是一樣的。

 

 

3.4 模型的預測功能

 

 

predict中有多種引數,比如Nodes,Proximity,predict.all。

 

 

[plain] view plain copy

  1. predict(object, newdata, type="response",  
  2.         norm.votes=TRUE, predict.all=FALSE, proximity=FALSE, nodes=FALSE,  
  3.         cutoff, ...)  
  4. #Nodes判斷是否是終點。Proximity判斷是否需要進行近鄰測量。predict.all判斷是否保留所有的預測器。  

 

舉例,以前面的隨機森林模型進行建模。

 

predict.all會輸出一個150*150的字元矩陣,代表每一顆樹的150個預測值(前面預設了ntree=100);

Nodes輸出100顆樹的節點情況。

 

[plain] view plain copy

  1. prediction <- predict(Randommodel, data[,1:5],type="class")  #還有response迴歸型別  
  2.   
  3. table(observed =data$Species,predicted=prediction)   

 

table輸出混淆矩陣,注意table並不是需要把預測值以及實際值放在一個表格之中,只要順序對上,用observed以及predicted直接呼叫也可以。

 

 

 

3.5 補充——隨機森林包(party包)

 

與randomForest包不同之處在於,party可以處理缺失值,而這個包可以。

 

[html] view plain copy

  1. library(party)  
  2.    #與randomForest包不同之處在於,party可以處理缺失值,而這個包可以  
  3. set.seed(42)  
  4. crf<-cforest(y~.,control = cforest_unbiased(mtry = 2ntree = 50), data=step2_1)  
  5. varimpt<-data.frame(varimp(crf))  

 

 

party包中的隨機森林建模函式為cforest函式,

mtry代表在每一棵樹的每個節點處隨機抽取mtry 個特徵,通過計算每個特徵蘊含的資訊量,特徵中選擇一個最具有分類能力的特徵進行節點分裂。