【機器學習】決策樹

來源 | AI小白入門
作者 | 文傑
編輯 | yuquanle
完整代碼見:原文鏈接

在這裏插入圖片描述

本文介紹了ID3,C4.5,CART三種基本的決策樹模型。首先介紹了決策樹的特徵選擇,包括信息增益,信息增益率、基尼指數、最小均方差分別對應分類樹ID3、C4.5、CART、迴歸樹CART。然後介紹了決策樹建樹的一般流程、對比分類樹和迴歸樹建樹的區別。最後介紹了樹模型中避免過擬合問題的剪枝方法,包括前剪枝和後剪枝。

決策樹簡介

決策樹是一種基本的分類和迴歸方法,用於分類主要是藉助每一個葉子節點對應一種屬性判定,通過不斷的判定導出最終的決策;用於迴歸則是用均值函數進行多次二分,用子樹中數據的均值進行迴歸。

決策樹算法中,主要的步驟有:特徵選擇,建樹,剪枝。接下來將介紹三種典型的決策樹算法:ID3,C4.5,CART。

優點

  • 可解釋性好,易可視化 ,特徵工程中可用特徵選擇。

  • 樣本複雜度O(log(n))O(log(n)),維度災難。

缺點

  • 易過擬合,學習最優模型N-P難,貪心搜索局部最優。

  • 雖然是非線性模型,但不支持異或邏輯。

  • 數據不均衡時不適合決策樹。

  • 決策屬性不可逆。

特徵選擇

對於決策樹而言,每一個非葉子節點都是在進行一次屬性的分裂,選擇最佳的屬性,把不同屬性值的樣本劃分到不同的子樹中,不斷循環直到葉子節點。其中,如何選擇最佳的屬性是建樹的關鍵,決策樹的一個特徵選擇的指導思想是熵減思想。

常見的選擇方式有ID3的信息增益,C4.5的信息增益率,CART的基尼指數,最小均方差。這裏分別介紹這ID3,C4.5,CART決策樹的特徵選擇標準

信息增益

爲了更清楚的理解信息增益這個概念,我們需要先來了解下信息論中的信息熵,以及條件熵的概念。

熵是一種對隨機變量不確定性的度量,不確定性越大,熵越大。

假設離散隨機變量YY的概率分佈爲P(Y)P(Y),則其熵爲:
H(Y)=yP(y)logP(y)=k=1KCkDlogCkD H(Y)=-\sum_{y}P(y)logP(y)\\ =-\sum_{k=1}^{K}\frac{|C_{k}|}{|D|}log\frac{|C_{k}|}{|D|}
其中熵滿足不等式0H(Y)logY0\leq H(Y) \leq log|Y|

在進行特徵選擇時儘可能的選擇在屬性XX確定的條件下,使得分裂後的子集的不確定性越小越好(各個子集的信息熵和最小),即P(YX)P(Y|X)的條件熵最小。
H(YX)=x,yP(x,y)log(P(yx))=xiXxi,yP(y,xi)logP(yxi)=i=1nXiXH(Xi) H(Y|X)=-\sum_{x,y}P(x,y)log(P(y|x))\\ =-\sum_{x_{i}\in X}\sum_{x_{i},y}P(y,x_{i})logP(y|x_i)\\ =-\sum_{i=1}^{n}\frac{|X_{i}|}{|X|}H(X_{i})\\
其中XiX_{i}是表示屬性XX取值爲ii構成的子集。

信息增益表示的就是在特徵XX已知的條件下使得類別YY的不確定性減少的程度。即爲特徵XX對訓練數據集DD的信息增益爲:
Gain(Y,X)=H(Y)H(YX) Gain(Y,X)=H(Y)-H(Y|X)
用信息增益來進行特徵選擇,的確可以選擇出那些對於類別敏感的特徵。

值得注意的是,信息增益沒有考慮屬性取值的個數的問題。因爲劃分的越細,不確定性會大概率越小,因此信息增益傾向於選擇取值較多的特徵。

如對於數據表中主鍵這樣的屬性,用信息增益進行屬性選擇,那麼必然會導致信息增益率最大,因爲主鍵與樣本是一一對應關係,而這樣做分類是無意義的,即信息增益不考慮分裂後子集的數目問題。

信息增益比

信息增益偏向於選擇特徵值取值較多的特徵,而信息增益比通過將訓練集關於特徵XX的信息熵作爲分母來限制這種傾向。

信息增益比定義爲信息增益比上特徵XX的信息熵:
Gainratio=Gain(Y,X)H(X) Gain_{ratio}=\frac{Gain(Y,X)}{H(X)}
其中H(X)=xP(x)logP(x)H(X)=-\sum_{x}P(x)logP(x)

基尼指數

基尼指數特徵選擇準則是CART分類樹用於連續值特徵選擇,其在進行特徵選擇的同時會決定該特徵的最優二分閾值。基尼指數是直接定義在概率上的不確定性度量:
Gini(D)=1k=1Kpk2=1i=1K(CkD)2 Gini(D)=1-\sum_{k=1}^{K}p_{k}^{2}\\=1-\sum_{i=1}^{K}\left(\frac{|C_{k}|}{|D|}\right)^{2}
可以看出,基尼指數與信息熵的定義極爲一致。

最小均方差

最小均方差應用於迴歸樹,迴歸問題一般採用最小均方差作爲損失。在特徵選擇的同時會測試不同的二分閾值的最小均方誤差,選擇最有的特徵和閾值:
minj,s[minc1xiR1(j,s)(yic1)2+minc2xiR2(j,s)(yic2)2] \min_{j,s}\left[ \min_{c_{1}}\sum_{x_{i}\in R_{1}(j,s)}(y_{i}-c_{1})^{2} + \min_{c_{2}}\sum_{x_{i}\in R_{2}(j,s)}(y_{i}-c_{2})^{2}\right]
其中cic_{i}是第ii個模型的迴歸值。

特徵選擇準則對比

  • ID3採用信息增益,C4.5採用信息增益率,CART分類採用基尼指數,CART迴歸採用最小均方誤差;

  • 信息增益,信息增益率,基尼指數都是用於分類樹,最小均方誤差用於迴歸樹;

  • 信息增益,信息增益率同樣可以處理連續值得情況,一般來講連續值的處理只作二分,所以CART迴歸是一個標準的二叉樹形式。

建樹

ID3和C4.5,CART分類樹

  • 輸入:訓練集DD,特徵集AA,閾值ϵ\epsilon

  • 輸出:決策樹TT

  1. DD中所有樣本屬於同一類CkC_{k}TT爲葉子節點,並將該葉子節點的類別標記爲CkC_{k},返回上一次遞歸。

  2. A=A=\varnothing,即所有的屬性都使用完了,TT爲葉子節點,並把該子集中最多一類CkC_{k}標記爲該葉子節點的類別,返回上一次遞歸。否則,3)

  3. 進行特徵選擇。選擇信息增益(信息增益比,基尼指數)最大的特徵AgA_{g},如果AgA_{g}的信息增益(信息增益率,基尼指數)小於預設的閾值ϵ\epsilon,同樣TT爲葉子節點,並把該子集中最多一類CkC_{k}標記爲該葉子節點的類別,返回上一次遞歸。否則,4)

  4. 符合建樹要求。對AgA_{g}的每一個可能值aia_{i},依次Ag=aiA_{g}=a_{i}DD分割爲若干個非空子集DiD_{i},將DiD_{i}中實例最多的類別標記爲該節點的類別CkC_{k},依次以DiD_{i}爲樣本集,AAgA-A_{g}爲特徵集,遞歸的調用(1-4)步,直到結束。

CART迴歸樹

由於迴歸樹不存在剩餘樣本屬於一類或者特徵用完的情況,所以分類樹沒有前面的前面兩步。

  1. 對每一個特徵進行步長(樣本)循環搜索不同閾值下的最小的均方誤差記爲該特徵的均方誤差,從所有特徵的均方誤差選擇出最小均方誤差。如果最小均方誤差小於預設的最小誤差,或者分裂後的子集的樣本數小於預設的最小值,則進行建立葉子節點TT,返回上一次遞歸。

  2. 否則,以特徵AgA_{g}作爲分裂屬性,根據閾值ϕ\phi進行二分,建立左右子樹,建立線性迴歸模型。遞歸(1-2)步,直到結束。

分類樹和迴歸樹建樹區別:

  • 迴歸樹中特徵可以重複進行選擇,而分類樹的特徵選擇只能用一次。

  • 迴歸樹比分類樹少了特徵集合爲空,樣本集合同屬一類這兩個返回標誌,只能人工干預(指標無提升)。

  • 對於特徵下劃分閾值的分裂,一般只作二分裂,不然就成了密度估計問題了。

剪枝

決策樹生成算法遞歸生成的決策樹,按照建樹的過程直到結束。這樣產生的決策樹往往對訓練集的分類很準確,但是對未知數據卻沒有那麼準確,容易出現過擬合現象。因此,決策樹需要藉助驗證集來進行剪枝處理,防止決策樹過擬合。

預剪枝

預剪枝是在構造決策樹的過程中,對比屬性劃分前後決策樹在驗證集上是否由精度上的提高。由於非葉子節點中的樣本往往不屬於同一類,採用多數樣本標記爲該節點的類別進行決策。若劃分後的決策樹在精度上有提高,則正常分裂,否則進行剪枝。其過程是一個貪心過程,即每一次劃分都必須使得決策精度有所提高。

當然也可以對建樹進行約束,比如信息增益小於一定閾值的情況或者建樹之後其中一個子集的樣本數小於一定數量進行預剪枝,統計學習方法書中採用熵加葉子節點樹作爲損失函數來控制預剪枝。

後剪枝

後剪枝是在決策樹建立後以後,自底向上的對決策樹在驗證集上對每一個非葉子節點判斷剪枝前和剪枝後的驗證精度,若剪枝後對驗證精度有所提高,則進行剪枝。

不同於預剪枝的是,預剪枝是對劃分前後的精度進行比較,而後剪枝是對剪枝前和剪枝後的驗證精度進行比較,相對於預剪枝,後剪枝決策樹的欠擬合風險小,泛化能力優於預剪枝,但時間開銷大。

決策樹總結

  • ID3,C4.5,CART沒有必要嚴格按照特徵選擇方式,建樹過程嚴格劃分。

  • 決策樹選擇從問題出發,如果是迴歸問題,可以採用CART迴歸樹,如果是分類問題那麼採用分類樹。

  • 決策樹選擇從數據出發,如果屬性是連續值,二分離散化建二叉樹,如果屬性是離散值,則建多叉樹。

  • 特徵選擇準則可以互用,一般來講連續值得特徵可以反覆選擇,而離散值的特徵只能用一次。

代碼實戰


double calcShannonEntOrGini(const DataStr &data, const string &type) 
{ 
 unsigned int i; 
 map<string,double> label_value;//每一類樣本的個數統計 
 double prob=0; 
 double shannoEnt=0; 
 double Gini=1; 
 string label; 
 for(i=0; i<data.size(); i++) 
 { 
 label=data[i][data[0].size()-1]; 
 if(label_value.count(label)) 
 label_value[label]+=1;//如果類別已初始化則在之前的基礎上加1 
 else 
 label_value[label]=1;//如果類別未初始化,則把當前類別下樣本數初始化爲1 
 } 
 //統計該子數據集上的所有樣本的決策屬性以及不同決策屬性上樣本數 
 for(map<string,double>::iterator it=label_value.begin();it!=label_value.end();it++) 
 { 
 prob=it->second/data.size(); 
 shannoEnt-=prob*log(prob); 
 Gini-=prob*prob; 
 } 
 //cout<<"shannoEnt="<<shannoEnt<<endl; //檢測信息熵計算是否正確 
 if(type=="Gini") 
 return Gini; 
 if(type=="Ent") 
 return shannoEnt; 
 return shannoEnt; 
 }

更多AI、NLP乾貨資源請關注公衆號:AI小白入門(ID: StudyForAI)
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章