決策樹(一)決策樹分類


決策樹

與SVM類似,決策樹在機器學習算法中是一個功能非常全面的算法,它可以執行分類與回歸任務,甚至是多輸出任務。決策樹的算法非常強大,即使是一些復雜的問題,也可以良好地擬合復雜數據集。決策樹同時也是隨機森林的基礎組件,隨機森林在當前是最強大的機器學習算法之一。

在這章我們會先討論如何使用決策樹訓練、可視化、以及做預測。然后我們會使用sk-learn過一遍CART訓練算法。接着我們會討論如何正則化樹,並將它們用於回歸任務。最后,我們會討論決策樹的一些不足。

 

訓練與可視化決策樹

為了理解決策樹,我們首先構造一個決策時並看看它如何做預測。下面的代碼在iris 數據集上訓練一個DecisionTreeClassifier:

from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier

iris = load_iris()
X = iris.data[:, 2:] # petal length and width
y = iris.target

tree_clf = DecisionTreeClassifier(max_depth=2)
tree_clf.fit(X, y)

 

接下來可視化這個訓練好的決策樹。首先使用export_graphviz() 方法輸出一個圖定義文件,命名為iris_tree.dot:

from sklearn.tree import export_graphviz

export_graphviz(
        tree_clf,
        out_file="iris_tree.dot",
        feature_names=iris.feature_names[2:],
        class_names=iris.target_names,
        rounded=True,
        filled=True
)

 

然后我們可以使用dot命令行工具(出自Graphviz包)將這個.dot 文件轉化為一個其他的格式,如PDF或PNG等。下面的命令會將這個.dot 文件轉換為一個 .png 文件:

$ dot -Tpng iris_tree.dot -o iris_tree.png

 

生成的圖為:

 

做預測

根據生成的圖,我們看一下決策樹如何做決策。假設我們現在有了一條 iris flower數據並希望對它進行分類。我們首先從根節點開始(深度為0,在最頂端):這個節點會判斷這支花的petal length 是否小於2.45cm。假設它是,則移動到左子節點(深度1,左)。在這個例子中,這個左子節點是一個葉子節點,所以它不會繼續進行判斷,僅檢查這個節點的類別,然后決策樹便會預測這支花是一個Iris setosa類被(class=setosa)。

可以看到,決策樹一個很好的特性就是:它們需要的數據准備操作很少。實際上,它們也不需要進行特征縮放或是數據中心化。

每個節點的sample屬性統計的是:有多少條訓練數據符合此節點。例如,100條訓練數據的pental length 大於2.45cm(深度1,右)。

每個節點的value屬性可以告訴我們:在每個類別中,有多少條訓練數據符合這個節點。例如,在最底層右邊的節點中,有0條數據屬於Iris setosa,1條數據屬於Iris versicolor,以及45條數據屬於virginica。

最后,每個節點的gini屬性衡量的是它的不純度(impurity):如果節點中所有的訓練集數據均屬於同一個類別,則這個節點的gini指數為0(gini=0),說明此節點為一個“純”(pure)節點。例如,在深度1的左邊節點中,所有的訓練數據都屬於Iris setosa類別,所以這個節點是“純”的,並且gini分數為0。下面是訓練算法計算gini分數的公式,Gi 為第 ith 個節點的gini分數:

 

在這個公式中,pi,k 是:在節點ith屬於類別k的實例數占(這個節點中)訓練數據實例數的比例。在深度2的左節點中,gini分數為:1 – (0/54)2 – (49/54)2 – (5/54)2 ≈ 0.168

需要注意的是,sk-learn使用的是CART算法,它僅生成二叉樹(也就是節點僅會判斷“是/否“問題)。不過其他算法如ID3可以生成多叉樹。

下圖是決策數的決策邊界。豎着的那條實現代表的是根節點(深度0)的決策邊界:petal length=2.45cm這條線。由於左邊區域是“純“的(僅有Iris setosa類別),所以它無法再分割。不過右邊的區域是”不純“的,所以深度為1 的右節點可以在petal width=1.75cm處再次分割(由橫着的虛線表示)。由於在訓練時參數max_depth 設置為2,這個決策樹會在此停止。如果設置max_depth=3,則兩個深度為2的節點還會增加其他的決策邊界(下圖中虛線點表示)。

 

 

決策樹是非常直觀的,並且決策邊界也非常容易解釋,類似這種模型一般稱為白盒模型。相反的,也有黑盒模型,例如我們之后會看到的隨機森林以及神經網絡。這些模型的預測表現非常好,但是一般很難以一種簡潔的方式去解釋它們這樣做預測的原因。例如,假設有一個神經網絡判斷到某張圖片上有某個人,我們很難知道到底是什么促成了這個預測:是這個模型預測到了這個人的眼睛?耳朵?還是鼻子?亦或是他們坐的那張椅子?與之相反的是,決策樹可以提供一個非常好、且簡單的分類規則。

 

估計類別概率

決策樹也可以用於估計:一個實例屬於某個特定類別k的概率。首先它會遍歷樹,以在葉子節點中找到這個實例,然后返回類別k的訓練數據在這個節點中的比例。例如,假設我們有支花,它的petal length = 5cm,petal width=1.5cm。則它對應的葉子節點為:深度為2的左節點。所以此時決策樹會輸出下面的概率:

  • 此花屬於Iris setosa類別(0/54)的概率為0
  • 此花屬於Iris versicolor類別(49/54)的概率為90.7%
  • 此花屬於Iris virginica類別(5/54)的概率為9.3%

如果用此模型做預測,則它會輸出Iris versicolor 類別(class 1),因為它的概率最高。下面我們驗證一下:

tree_clf.predict_proba([[5, 1.5]])
>array([[0.        , 0.90740741, 0.09259259]])

tree_clf.predict([[5, 1.5]])
>array([1])

 

可以看到與計算結果一致,並且這個推測的概率也可以直接在之前的決策邊界圖上計算到(右下角的那個圖里各個類別的概率)。

 

CART訓練算法

Sk-learn使用的是分類回歸樹算法(Classification and Regression Tree,CART)訓練的決策樹(也稱為“生長“樹(growing tree))。這個算法首先使用一個單個特征k以及一個閾值tk(例如petal length <= 2.45cm)將訓練集分割為兩個子集。它如何選擇k與tk呢?它會搜索(k, tk) 對,找出那個生成最純(purest)子集(根據它們的大小附加權重)的(k, tk) 對。下面是算法嘗試去最小化的損失函數:

在CART算法成功地將訓練接分成兩個子集后,它會再次使用同樣的邏輯分割剩下的子集,依次類推。直到達到了指定的最大深度(由max_depth 超參數指定),或者是無法再找到一個分割使得“不純度“更低時,則會停止。還有其他幾個超參數用於控制停止條件,分別是:min_samples_split, min_samples_leaf, min_weight_fraction_leaf, 以及 max_leaf_nodes)。

很明顯CART是一個貪心算法,它並不會檢查是否有另一套分割方法使得整體的“不純度“更低,而僅是檢查每層,讓這層的分割結果的”不純度“最低。貪心算法一般都能產生一個解,這種結果尚可,但是它不會保證結果是最優的。

找到最優樹是一個NP-完全問題(NP-Complete problem):它需要的時間復雜度是O(exp(m))。所以即使是一個較小的數據集,所花費的時間也會非常多。所以我們才會采用“結果尚可“的解法。

 

計算復雜度

在做預測時,從根節點遍歷數到葉子節點是一個必須的操作。決策樹一般是(近似)平衡的,所以遍歷決策樹需要遍歷大約O(log2(m)) 個節點。因為每個節點僅需要檢查一個特征的值,所以整個預測的復雜度是O(log2(m)),獨立於特征的數量。所以即使訓練集非常大,決策樹的預測操作也非常快。

訓練算法會比較每個節點上所有samples(見最開始的決策樹生成圖)的所有特征(如果設置了max_features 的話,會少一些),導致的訓練復雜度為O(n × m log2(m)) 。對於小的訓練集(幾千條數據)來說,sk-learn可以通過對數據進行預排序(presort,設置參數 presort=True)加快訓練速度。不過如果是更大型的數據集的話,則相反會減慢它的訓練速度。

 

Gini不純度還是熵

默認情況下會使用Gini不純度進行衡量,不過我們也可以選擇熵不純度(entropy impurity)進行衡量,設置超參數criterion 為entropy 即可。熵的概念來自於熱力學,用於衡量分子紊亂程度:如果分子靜止並且盡然有序,則熵接近於0。熵后來被引入到各個不同的領域,包括香農的信息論。在信息論中,熵被用於衡量一條消息中包含的平均信息量。如果所有的消息都是一樣的,則熵為0。在機器學習中,熵頻繁地用於衡量不純度:如果一個集合中包含的所有實例均為同一個類別,則這個集合的熵為0。下面的公式定義了第ith個節點的熵:

 

例如,對於深度為2的左節點(參考最開始訓練的決策樹),它的熵等於–(49/54) log2 (49/54) – (5/54) log2 (5/54) ≈ 0.445。

那到底是使用Gini不純度還是熵?實際上,大多數時候這兩個並沒有太大的區別:它們會生成相似的數。Gini不純度計算起來稍微快一些,所以它作為默認值是比較合適的。不過,當它們生成的樹有不同時,Gini不純度會傾向於將最頻繁的類別分離成一個枝干,而熵傾向於產生稍微更平衡一點的樹。

 

正則化超參數

 決策樹很少會對訓練數據做一些假設(做假設的例如線性模型,例如它會假設數據是線性的,決策樹與它不一樣)。如果無約束的話,樹的結構會自適應於訓練數據,並擬合地非常接近訓練集——也即是說很容易出現過擬合。這種模型一般稱為非參數模型(nonparametric model),不是因為它們沒有任何參數(它們一般有很多參數),而是因為參數的數量在訓練前是未知的。而例如線性模型這種,它的參數是預先決定的,所以它的自由度有限,也便減少了過擬合的風險(不過同樣也增加了欠擬合的風險)。

為了避免對訓練數據過擬合,我們需要在訓練時限制決策樹的自由度,這個便是我們常說的正則化。正則化的超參數取決於使用的算法,但是一般我們至少可以限制決策樹的深度。在sk-learn中,這個由超參數max_depth 控制(默認為 None,也就是無限制)。減少max_depth 的值會正則化模型,並因此減少過擬合的風險。

DecisionTreeClassifier類還有幾個其他參數可以簡單地限制決策樹的形狀:min_samples_split(一個節點必須最少要有這些數量的samples,才可以進行分裂),min_samples_leaf(一個葉子節點必須要有的sample個數),min_weight_fraction_leaf(與min_samples_leaf 一樣,不過是以所有帶權數據實例總數的比例表示的),max_leaf_nodes(葉子節點的最大數目),以及max_features(在每個節點中進行分割時,考慮的最多的特征數目)。增加 min_* 的超參數或者減少 max_* 的超參數可以對模型實施正則化。

其他有些算法會先訓練決策樹,訓練時不給任何限制,然后再進行剪支(pruning),也就是刪除不必要的節點。如果一個節點的所有子節點均為葉子節點,且它提供的純度並沒有一個顯著地提升的話,則這個節點被認為是不必要的節點。

下圖是在moons 訓練集上訓練的兩顆決策樹,左邊的決策樹是用默認的超參數訓練(也就是說沒有限制),右邊的指定了超參數min_samples_leaf=4。可以明顯看到左邊的存在過擬合,而右邊的泛化性能會更好:

 

 決策樹分類器介紹完之后,我們會繼續引入決策樹回歸。

 


免責聲明!

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



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