決策樹系列(三)——ID3
決策樹系列(三)——ID3
預備知識:決策樹
初識ID3
回顧決策樹的基本知識,其構建過程主要有下述三個重要的問題:
(1)資料是怎麼分裂的
(2)如何選擇分類的屬性
(3)什麼時候停止分裂
從上述三個問題出發,以實際的例子對ID3演算法進行闡述。
例:通過當天的天氣、溫度、溼度和季節預測明天的天氣
表1 原始資料
當天天氣 |
溫度 |
溼度 |
季節 |
明天天氣 |
晴 |
25 |
50 |
春天 |
晴 |
陰 |
21 |
48 |
春天 |
陰 |
陰 |
18 |
70 |
春天 |
雨 |
晴 |
28 |
41 |
夏天 |
晴 |
雨 |
8 |
65 |
冬天 |
陰 |
晴 |
18 |
43 |
夏天 |
晴 |
陰 |
24 |
56 |
秋天 |
晴 |
雨 |
18 |
76 |
秋天 |
陰 |
雨 |
31 |
61 |
夏天 |
晴 |
陰 |
6 |
43 |
冬天 |
雨 |
晴 |
15 |
55 |
秋天 |
陰 |
雨 |
4 |
58 |
冬天 |
雨 |
1.資料分割
對於離散型資料,直接按照離散資料的取值進行分裂,每一個取值對應一個子節點,以“當前天氣”為例對資料進行分割,如圖1所示。
對於連續型資料,ID3原本是沒有處理能力的,只有通過離散化將連續性資料轉化成離散型資料再進行處理。
連續資料離散化是另外一個課題,本文不深入闡述,這裡直接採用等距離資料劃分的李算話方法。該方法先對資料進行排序,然後將連續型資料劃分為多個區間,並使每一個區間的資料量基本相同,以溫度為例對資料進行分割,如圖2所示。
2. 選擇最優分裂屬性
ID3採用資訊增益作為選擇最優的分裂屬性的方法,選擇熵作為衡量節點純度的標準,資訊增益的計算公式如下:
其中, 表示父節點的熵; 表示節點i的熵,熵越大,節點的資訊量越多,越不純; 表示子節點i的資料量與父節點資料量之比。 越大,表示分裂後的熵越小,子節點變得越純,分類的效果越好,因此選擇 最大的屬性作為分裂屬性。
對上述的例子的跟節點進行分裂,分別計算每一個屬性的資訊增益,選擇資訊增益最大的屬性進行分裂。
天氣屬性:(資料分割如上圖1所示)
溫度:(資料分割如上圖2所示)
溼度:
季節:
由於最大,所以選擇屬性“季節”作為根節點的分裂屬性。
3.停止分裂的條件
停止分裂的條件已經在決策樹中闡述,這裡不再進行闡述。
(1)最小節點數
當節點的資料量小於一個指定的數量時,不繼續分裂。兩個原因:一是資料量較少時,再做分裂容易強化噪聲資料的作用;二是降低樹生長的複雜性。提前結束分裂一定程度上有利於降低過擬合的影響。
(2)熵或者基尼值小於閥值。
由上述可知,熵和基尼值的大小表示資料的複雜程度,當熵或者基尼值過小時,表示資料的純度比較大,如果熵或者基尼值小於一定程度時,節點停止分裂。
(3)決策樹的深度達到指定的條件
節點的深度可以理解為節點與決策樹跟節點的距離,如根節點的子節點的深度為1,因為這些節點與跟節點的距離為1,子節點的深度要比父節點的深度大1。決策樹的深度是所有葉子節點的最大深度,當深度到達指定的上限大小時,停止分裂。
(4)所有特徵已經使用完畢,不能繼續進行分裂。
被動式停止分裂的條件,當已經沒有可分的屬性時,直接將當前節點設定為葉子節點。
程式設計及原始碼(C#版本)
(1)資料處理
用二維陣列儲存原始的資料,每一行表示一條記錄,前n-1列表示資料的屬性,第n列表示分類的標籤。
static double[][] allData;
為了方便後面的處理,對離散屬性進行數字化處理,將離散值表示成數字,並用一個連結串列陣列進行儲存,陣列的第一個元素表示屬性1的離散值。
static List<String>[] featureValues;
那麼經過處理後的表1資料可以轉化為如表2所示的資料:
表2 初始化後的資料
當天天氣 |
溫度 |
溼度 |
季節 |
明天天氣 |
1 |
25 |
50 |
1 |
1 |
2 |
21 |
48 |
1 |
2 |
2 |
18 |
70 |
1 |
3 |
1 |
28 |
41 |
2 |
1 |
3 |
8 |
65 |
3 |
2 |
1 |
18 |
43 |
2 |
1 |
2 |
24 |
56 |
4 |
1 |
3 |
18 |
76 |
4 |
2 |
3 |
31 |
61 |
2 |
1 |
2 |
6 |
43 |
3 |
3 |
1 |
15 |
55 |
4 |
2 |
3 |
4 |
58 |
3 |
3 |
其中,對於當天天氣屬性,數字{1,2,3}分別表示{晴,陰,雨};對於季節屬性{1,2,3,4}分別表示{春天、夏天、冬天、秋天};對於明天天氣{1,2,3}分別表示{晴、陰、雨}。
(2)兩個類:節點類和分裂資訊
a)節點類Node
該類儲存了節點的資訊,包括節點的資料量、節點選擇的分裂屬性、節點輸出類、子節點的個數、子節點的分類誤差等。
View Code (篇幅限制,原始碼參見原微博)
b)分裂資訊類SplitInfo
該類儲存節點進行分裂的資訊,包括各個子節點的行座標、子節點各個類的數目、該節點分裂的屬性、屬性的型別等。
View Code(篇幅限制,原始碼參見原微博)
(3)節點分裂方法findBestSplit(Node node,List<int> nums,int[] isUsed),該方法對節點進行分裂,返回值Node
其中:
node表示即將進行分裂的節點;
nums表示節點資料對應的行座標列表;
isUsed表示到該節點位置所有屬性的使用情況(1:表示該屬性不能再次使用,0:表示該屬性可以使用);
findBestSplit主要有以下幾個組成部分:
1)節點分裂停止的判定
判斷節點是否需要繼續分裂,分裂判斷條件如上文所述。原始碼如下:
View Code(篇幅限制,原始碼參見原微博)
2)尋找最優的分裂屬性
尋找最優的分裂屬性需要計算每一個分裂屬性分裂後的資訊增益,計算公式上文已給出,其中熵的計算程式碼如下:
View Code(篇幅限制,原始碼參見原微博)
3)進行分裂,同時子節點也執行相同的分類步驟
其實就是遞迴的過程,對每一個子節點執行findBestSplit方法進行分裂。
全部原始碼:
View Code(篇幅限制,原始碼參見原微博)
(注:上述程式碼只是ID3的核心程式碼,資料預處理的程式碼並沒有給出,只要將預處理後的資料輸入到主方法findBestSplit中,就可以得到最終的結果)
總結
ID3是基本的決策樹構建演算法,作為決策樹經典的構建演算法,其具有結構簡單、清晰易懂的特點。雖然ID3比較靈活方便,但是有以下幾個缺點:
(1)採用資訊增益進行分裂,分裂的精確度可能沒有采用資訊增益率進行分裂高
(2)不能處理連續型資料,只能通過離散化將連續性資料轉化為離散型資料
(3)不能處理預設值
(4)沒有對決策樹進行剪枝處理,很可能會出現過擬合的問題