0 通俗的理解
對於一個根據特征向量來對樣本進行分類的問題,首先挑出一個最有價值的特征,對該特征進行提問,如樣本顏色是什么;然后根據得到的不同回答,如紅色、藍色等,將數據集划分成子集,對每個子集重復上述操作,也就是說總是在剩下的特征集合里面找一個對最終分類任務最有用的特征,根據不同的取值再划分成更小的子集,知道最終子集內的樣本都屬於或者幾乎屬於同一類,那么此時我們就認為模型已經訓練好。 (提問即決策規則,把提問保留來划分子集 ‘依據’)
決策樹也是用來處理有監督的分類問題。它處理的數據的特征往往也是類別變量,而不是連續值。(SVM、邏輯斯蒂回歸、線性回歸都默認做分類預測的樣本的特征向量是連續值)
當然,決策樹也是可以處理連續變量的分類的。通常決策樹適合處理特征向量中類別變量比較多的任務,以及對模型的可解釋性要求較高的任務。
1 模型思路與算法流程
(1)模型思路
選擇特征(選擇順序有策略,先對重要特征提問,再慢慢偏向細節),提問過程組成了一棵樹的結構。
決策樹模型不但能預測出類別,還能告訴用戶它是根據哪些特征、如何判斷,猜得到最終預測結果的。
(2)基本流程
a. 輸入訓練集S;
b. 若S中的所有樣本為同一類別,標記為該類別,return;
c. 若S中的所有樣本各個特征均相同,標記為數目最多的類別,return;
d. 待划分集合M初始化為S,初始化根節點root;
重復以下操作:
在所有特征中找到最優的特征α*,根據α*的不同取值將M划分成不同的子集,記為U1,U2,U3,...,並產生一個划分節點node。
對於每個子集Un的處理方式如下:
①如果無法划分,以最多類別作為預測類別,成為樹的一個葉子,return;
②如果無須划分,將該子集樣本類別作為預測類別,成為樹的一個葉子,return;
③如果不是以上兩種情況,則把該子集作為待划分集合M,成為上次划分的節點的孩子節點,重復步驟d。
注:①和②其實是兩種停止條件,無須划分是說自己內的所有樣本已經是同一類別了,沒必要划分了;無法划分是指子集內的樣本特征都是一樣的,但是類別不同,同樣無法繼續划分。
e. 待全部划分結束,可得一棵以root為根節點的決策樹。
(3)決策樹模型的關鍵問題——特征的優選
在遍歷所有的特征時,需要根據以該特征划分得到子集的純度為這些特征打分,從而選取最優特征,那么,這個分數該如何計算呢???
計算該特征的分數就是計算划分后子集的純度。即該特征划分以后,子集的純度比未划分時增加了多少,增加的多,說明該特征更有用,所以應該給分高一些;反之,說明基於該特征的划分作用不大,應該給分低一些。
(自己的理解:純度就是某一特征中類別的分布,某一類所占比重明顯大的話,說明樣本集比較純)
2 特征選擇原則
(1)信息增益原則(Information Gain Criteria)
定義:用信息量的變化來度量按照某個特征划分后,自己的純度的增加程度。
信息量即一個事件包含的信息的量。在信息論中,通常用信息熵(熵,Entropy)對隨機事件的信息進行度量。信息熵表示一個隨機事件的不確定程度,即混亂程度。其數學公式為:
$H(X) = -\sum _{i=1}^{k}p_{i}logp_{i}$
其中,X是一個隨機事件,總共有k種可能的情況,每種情況發生的概率分別為p1,p2,...,pk 。
在決策樹特征選擇與節點分裂時,將該節點上包含的訓練集樣本的類別看成一個隨機事件,通過統計各類別的比例,代替上面各類別的比例,代替上面各種情況中的概率,就可以計算出某個節點的信息熵。
信息增益:指的是按照某個特征將節點分裂后,相對於分裂前的節點,分裂后的各個子節點的加權平均信息熵減少了多少。即通過某個特征的輔助,對於樣本集類別的認知的不確定性消除了多少。
信息增益的數學形式:
$InfoGain(X,F) = H(X) - \sum _{i}\frac{X_{i}}{X}H(X_{i})$
其中,X為划分前的數據集,F為用來划分的特征,Xi為划分后每個集合的數據集。
(2)信息增益比原則
定義:信息增益與特征本身的信息熵的比值。
信息增益原則有缺陷,即其傾向於情況更多的特征。但多數情況下,這種特征過於細致,不能真正表達特征與類別的關系,容易過擬合。
這種特征有一個共同點,即本身的取值比較多,也就是特征本身的信息熵較大。因此,通過改進,得到信息增益比原則。數學形式如下:
$InfoGainRatio(X,F) = InfoGain(X,F) / H(F)$
(3)基尼系數原則
基尼系數依舊是用來度量集合中樣本類別純度的方法。數學含義是:在一個集合中任意取出兩個樣本,其不屬於同一類的概率。
基尼系數的計算公式:
$Gini(S) = 1 - \sum _{i}p_{i}^{2}$
其中,pi為取到的樣本為第i類的概率。
集合越“純”,即類別越單一,取到同一樣本的概率就越大,基尼系數越小。所以,我們更加傾向於選擇分裂之后基尼系數的加權和最小的划分方式。作為決策樹特征選擇的基尼系數公式為:
$GiniInd(N,a) = \sum _{i=1}^{k}\frac{|N_{i}|}{|N|}Gini(N_{i})$
其中,N為節點分裂前的集合;Ni為分割成的子集合;a為用來分裂的特征。最終的目標特征式為:
$a^{*} = arg min GiniInd(N,a)$
3 剪枝策略
剪枝是防止決策樹模型過擬合的策略之一。於決策樹而言,模型的復雜度是分支的多少。剪枝操作就是將無益於模型泛化能力提高的節點分支“剪掉”。
拋出一個問題。如何判斷有益還是無益?答案是 基於驗證集的檢驗來判斷是否剪枝的。
剪枝的具體操作如下:
對於一個節點來說,如果分裂后比分裂前在驗證機上表現得更好,那么就允許這個節點分裂,形成“樹枝”;反之,如果一個節點在分裂后反而在驗證集上的表現更差了,那么就不希望這個節點分裂,就需要把已經分裂的“樹枝”進行“剪枝”,避免模型的泛化能力下降。
剪枝分為預剪枝和后剪枝。
預剪枝:選擇特征分裂節點過程中,如果判斷一個節點需要剪枝,那么就直接不對該節點進行分裂。(缺點,可能錯失更優解)
后剪枝:先分裂,得到一棵完整的決策樹后,再考察每個節點,對需要剪枝的節點進行剪枝處理。(缺點,計算量大很多)
4 常用決策樹模型
(1)ID3算法
ID指的是Iterative Dichotomister ,即迭代二分法。
①如果集合(節點)無法划分或無須划分,則返回該節點。其中,無法划分的用樣本數最多的類別表示該節點預測類別,無須划分的用樣本的類別表示該節點預測類別,否則轉入步驟②。
②計算現有集合(節點)的信息熵。對於所有的特征,分別計算以其為划分標准所得的子集的信息熵(各個子集加權平均),選擇能使信息增益最大的特征。
③如果信息增益大於設定的闞值,那么選擇該特征分裂節點,並轉入步驟④,否則返回該節點。
④對於分裂得到的各個子集(子節點),重復步驟①-③。
(2)C4.5算法(ID3的改進)
①如果集合(節點)無法划分或無須划分,則返回該節點。其中,無法划分的用樣本數最多的類別表示該節點預測類別,無須划分的用樣本的類別表示該節點預測類別,否則轉入步驟②。
②計算現有集合(節點)的信息熵。對於所有的特征,分別計算以其為划分標准所得的子集的信息熵(各個子集加權平均)及特征本身的信息熵,選擇能使信息增益比最大的特征。
③如果信息增益大於設定的闞值,那么選擇該特征分裂節點,並轉入步驟④,否則返回該節點。
④對於分裂得到的各個子集(子節點),重復步驟①-③。
5 多變量決策樹
基本思想:在每個節點都用多個特征共同參與決策。
具體實現:在每個節點用一個線性分類器代替單一屬性的閾值。
6 代碼實現
決策樹預測鳶尾花數據集

1 from sklearn.datasets import load_iris 2 from sklearn.tree import DecisionTreeClassifier, export_graphviz 3 from sklearn.model_selection import train_test_split 4 import graphviz 5 import os 6 7 # 加載Iris數據集 8 iris = load_iris() 9 # 獲取數據與類別標簽 10 iris_data = iris.data 11 iris_target = iris.target 12 # 類別標簽名稱 13 iris_target_names = iris.target_names 14 # 用來訓練的特征名稱 15 iris_feat_names = iris.feature_names 16 # 打印類別和特征名稱 17 print(iris_feat_names) 18 print(iris_target_names) 19 20 # 對數據集進行划分,將30%的數據用來做測試集,其余作為訓練集 21 X_train, X_test, y_train, y_test = train_test_split(iris_data, iris_target, test_size=0.3, random_state=2019) 22 print(X_train.shape, X_test.shape, y_train.shape, y_test.shape) 23 24 # # 建立決策樹模型,采用信息增益准則,最優值處划分,最大深度不設定,即不限制深度 25 # clf = DecisionTreeClassifier(criterion='entropy', splitter='best', max_depth=None, random_state=2019) 26 # clf.fit(X_train, y_train) 27 # # 計算訓練集和測試集精度 28 # train_acc = sum(clf.predict(X_train) == y_train)/len(y_train) 29 # test_acc = sum(clf.predict(X_test) == y_test)/len(y_test) 30 # print('Train Accuracy is : {:.2f}'.format(train_acc)) 31 # print('Test Accuracy is : {:.2f}'.format(test_acc)) 32 #為避免過擬合,最大深度設為3 33 clf=DecisionTreeClassifier(criterion='entropy',splitter='best',max_depth=3, random_state=2019) 34 clf.fit(X_train, y_train) 35 train_acc = sum(clf.predict(X_train) == y_train)/len(y_train) 36 test_acc = sum(clf.predict(X_test) == y_test)/len(y_test) 37 print('Train Accuracy is : {:.2f}'.format(train_acc)) 38 print('Test Accuracy is : {:.2f}'.format(test_acc)) 39 #Graphviz對決策樹進行可視化 40 dot_data = export_graphviz(clf, feature_names=iris_feat_names, out_file=None) 41 dot = graphviz.Source(dot_data) 42 dot.view()
可視化結果: