決策樹
熵的定義
如果一個隨機變量X的可能取值為X={x1,x2,..,xk},其概率分布為P(X=x)=pi(i=1,2,...,n),則隨機變量X的熵定義為\(H(x) = -\sum{p(x)logp(x)}=\sum{p(x)log{\frac{1}{p(x)}}}\)。需要注意的是,熵越大,隨機變量的不確定性就越大。
當n = 2的時候,\(H(p)=-plogp-(1-p)log(1-p)\)也就是交叉熵的損失函數。
條件熵
條件熵主要是用來計算,在莫一列數據X選中的條件下,其標簽Y的熵大小,這樣可以幫助計算,那一列數據對應的標簽更加簡潔易分。 條件熵計算公式如下,其中,\(p_i =P(X=x_i)\)
具體來說,條件熵公式如何使用到結構化的數據中來的,這里的X表示的某一列的特征,Xi表示該特征的一個子類特征,這里\(H(Y_i)\)表示Xi這一類子特征對應的標簽Y的熵。K表示標簽的類別,下面公式中,\(Y_{ik}\),表示第Xi類特征對應的標簽\(Y_i\)的種類。
舉個具體的例子:
| 特征X | 標簽Y |
|---|---|
| 1 | 1 |
| 1 | 0 |
| 1 | 1 |
| 1 | 1 |
| 2 | 1 |
| 2 | 1 |
| 2 | 0 |
這對特征Xi = 1的條件熵的計算如下:
信息增益
信息增益的計算方式如下,其中,由於H(D)是個固定值,H(D|A)越小,信息增益就越大,這樣這個特征就越簡潔,也就是說這個特征能夠最大化的去區分label , 這里 X代表的是莫一列特征,Y代表的是數據集的標簽。
決策樹算法
ID3
ID3 算法和原理就是,使用信息增益來挑選特征,優先挑選信息增益最大的特征。其具體決策樹生成過程如下:
1. 首先計算所有特征的信息增益,挑選一個最大的特征,作為節點的特征
2. 對挑選出來的子節點遞歸調用方法 1
3. 當特征信息增益小於閾值,或者沒有特征可以選擇,或者可選特征小於閾值等,停止。
C4.5算法
上述算法有一個問題,假設特征X有兩列特征,其信息增益差不多,但是某一列數據特別混亂,這個時候應該避免選擇這一列作為根結點,而C4.5算法的核心就是通過給信息增益下面,除一個這一列特征的熵,從而減少這一列數據的信息增益。也就是說,如果某一列特征越混亂,那么其最終得到的信息增益就越小,從而避免了上述的問題。 具體公式為:
其中,n為
CART算法
CART算法的思路和上面兩個算法是一樣的,只不過這里用來評估特征混亂度的方法是用的基尼指數。其中,基尼指數越大,不確定性越大,和熵是類似的。
基尼指數的定義如下:其中,\(p_k\)為樣本點屬於第k類的概率。
如果將基尼指數用到結構化數據集中:
在特征為X標簽為Y的條件下,其基尼指數為:其中,\(Y_1,Y_2\)表示,特征X下的子類別\(X_1,X_2\)對應的標簽。
決策樹剪肢
決策樹減肢可以減輕決策樹的復雜度,同時確保決策樹能夠保持一定的正確率,剪肢的方法,一般是從最深的一層開始,減去節點,然后看accuracy,如果accuracy提升了,就可以減去。也可以使用其他基於閾值的方法,例如下一層的不純度低於某個閾值,就可以直接不分裂等等。
sklearn中決策樹的使用
參數
class sklearn.tree.DecisionTreeClassifier(*, criterion='gini',
splitter='best', max_depth=None, min_samples_split=2, min_samples_leaf=1,
min_weight_fraction_leaf=0.0, max_features=None, random_state=None,
max_leaf_nodes=None, min_impurity_decrease=0.0, min_impurity_split=None,
class_weight=None, ccp_alpha=0.0)
criterion{“gini”, “entropy”}, default=”gini” 確定決策樹是基於基尼指數還是熵
max_depth 樹的層數,限制樹的最大深度,超過設定深度的樹枝全部剪掉,這是用得最廣泛的剪枝參數,在高維度低樣本量時非常有效。決策樹多生長一層,對樣本量的需求會增加一倍,所以限制樹深度能夠有效地限制過擬合。在集成算法中也非常實用。實際使用時,建議從=3開始嘗試,看看擬合的效果再決定是否增加設定深度。實際層數為 max_depth +1 考慮根
min_impurity_decrease 限制決策樹的生長,如果節點的不純度(GINI,GAIN)小於這個閾值,就不在生成子節點
min_impurity_split :不純度必須大於這個值,不然不分裂
min_impurity_decrease限制信息增益的大小,信息增益小於設定數值的分枝不會發生。這是在0.19版本種更新的功能,在0.19版本之前時使用min_impurity_split。
random_state 隨機數種子,固定種子之后,訓練的模型是一樣的
class_weight 可以用來定義某一個類別的權重,讓這一個類比在計算的時候,信息增益變得稍微大一些
splitter也是用來控制決策樹中的隨機選項的,有兩種輸入值,輸入”best",決策樹在分枝時雖然隨機,但是還是會優先選擇更重要的特征進行分枝(重要性可以通過屬性feature_importances_查看),輸入“random",決策樹在分枝時會更加隨機,樹會因為含有更多的不必要信息而更深更大,並因這些不必要信息而降低對訓練集的擬合。這也是防止過擬合的一種方式。當你預測到你的模型會過擬合,用這兩個參數來幫助你降低樹建成之后過擬合的可能性。當然,樹一旦建成,我們依然是使用剪枝參數來防止過擬合。所以要想泛化好,最好splitter設置成random。
和剪肢相關的參數:
min_samples_leaf ** ** 限定,一個節點在分枝后的每個子節點都必須包含至少min_samples_leaf個訓練樣本,否則分枝就不會發生,或者,分枝會朝着滿足每個子節點都包含min_samples_leaf個樣本的方向去發生
一般搭配max_depth使用,在回歸樹中有神奇的效果,可以讓模型變得更加平滑。這個參數的數量設置得太小會引起過擬合,設置得太大就會阻止模型學習數據。一般來說,建議從=5開始使用。如果葉節點中含有的樣本量變化很大,建議輸入浮點數作為樣本量的百分比來使用。同時,這個參數可以保證每個葉子的最小尺寸,可以在回歸問題中避免低方差,過擬合的葉子節點出現。對於類別不多的分類問題,=1通常就是最佳選擇。
min_samples_split限定,一個節點必須要包含至少min_samples_split個訓練樣本,這個節點才允許被分枝,否則分枝就不會發生。
max_features限制分枝時考慮的特征個數,比如一個樣本特征為13個,限制之后只能使用有限個特征進行分類任務。超過限制個數的特征都會被舍棄。和max_depth異曲同工,max_features是用來限制高維度數據的過擬合的剪枝參數,但其方法比較暴力,是直接限制可以使用的特征數量而強行使決策樹停下的參數,在不知道決策樹中的各個特征的重要性的情況下,強行設定這個參數可能會導致模型學習不足。如果希望通過降維的方式防止過擬合,建議使用PCA,ICA或者特征選擇模塊中的降維算法。
class_weight 標簽權重,給某一類的標簽更大的權重,當樣本不均衡的時候,可以考慮使用
min_weight_fraction_leaf有了權重之后,樣本量就不再是單純地記錄數目,而是受輸入的權重影響了,因此這時候剪枝,就需要搭配min_ weight_fraction_leaf這個基於權重的剪枝參數來使用。另請注意,基於權重的剪枝參數(例如min_weight_ fraction_leaf)將比不知道樣本權重的標准(比如min_samples_leaf)更少偏向主導類。如果樣本是加權的,則使用基於權重的預修剪標准來更容易優化樹結構,這確保葉節點至少包含樣本權重的總和的一小部分。
注意在sklearn中實現的決策樹都是二叉樹
使用模型訓練數據:
model = tree.DecisionTreeClassifier()
model.fit(X,y)
model.predict(X_val)
sklearn中,可以輸出決策樹特征的重要性
clf.feature_importances_
回歸樹
在分類問題中決策樹的每一片葉子都代表的是一個 class;在回歸問題中,決策樹的每一片葉子表示的是一個預測值,取值是連續的。
決策樹還可以做回歸任務,回歸樹種的參數和上面分類樹的參數是一模一樣的,唯一的區別是,回歸樹沒有class_weight這個參數,因為沒有類別不平衡這個說法
X = [[0, 0], [2, 2]]
y = [0.5, 2.5]
clf = tree.DecisionTreeRegressor()
clf = clf.fit(X, y)
clf.predict([[1, 1]])
array([0.5])
決策樹可視化
可以使用graphviz安裝包:pip install graphviz
一個例子:
這里的參數,class_names 表示類別的名稱,filled表示填充顏色,rounded 表示框的形狀
feature_name = ["A","B","C"]
import graphviz
dot_data = tree.export_graphviz(clf
,feature_names= feature_name
,class_names=["1","2","3"]
,filled=True
,rounded=True
,out_file=None
)
graph = graphviz.Source(dot_data)
graph
