1. 程式人生 > >《Machine Learning in Action》—— Taoye給你講講決策樹到底是支什麼“鬼”

《Machine Learning in Action》—— Taoye給你講講決策樹到底是支什麼“鬼”

# 《Machine Learning in Action》—— Taoye給你講講決策樹到底是支什麼“鬼” 前面我們已經詳細講解了線性SVM以及SMO的初步優化過程,具體可看: * [《Machine Learning in Action》—— 剖析支援向量機,優化SMO](https://mp.weixin.qq.com/s?__biz=MzI4NjMyMDM4Mg==&mid=2247484159&idx=1&sn=4d31214dbab885456f24b4291a0d58ee&chksm=ebdff16edca87878341c7ab922d62935aecafccfc948ea899fbc12116cb4bac98ec042c7cf9e&token=1005165967&lang=zh_CN#rd) * [《Machine Learning in Action》—— 剖析支援向量機,單手狂撕線性SVM](https://mp.weixin.qq.com/s?__biz=MzI4NjMyMDM4Mg==&mid=2247484147&idx=1&sn=a823c20a4a02b819487a491a34771eec&chksm=ebdff162dca87874e33ae6d8fdc0026e1d15bfeb683b6d4451b05b844b37139c2019feb0d2b9&token=1005165967&lang=zh_CN#rd) 關於SVM非線性相關的內容,我們留著下個星期來撕 這篇文章我們先來看看決策樹的內容,決策樹相對於SVM來講要簡單不少,也沒有多麼複雜的公式。我理解的決策樹,簡單來說就是**通過已有的資料集訓練出一個樹形結構的模型,以便我們能夠依據該模型對不知分類結果的資料進行預測。**簡單的決策樹就有點類似於我們在學習資料結構時候的二叉排序樹。當然了,決策樹除了能夠進行分類之外,還能進行迴歸,這裡主要討論的是分類問題。 關於決策樹相關的內容,可能會肝兩篇文章來介紹。第一篇主要是講解決策樹先關的基本知識,及其決策訓練的過程,也就是我們的這篇文章,重在理論及推導,也重在理解。而第二篇文章寫的主要內容是決策樹的程式碼實戰,而程式碼實戰是在熟悉理論基礎的前提之下來進行的,所以對於決策樹相關的理論知識還是有必要了解的。可能的話,還會有第三篇,主要是關羽防止決策樹過擬合的剪枝操作的內容。 ## 一、什麼是決策樹 關於決策樹的定義,李航——《統計學習方法》(第二版)這本書中是這樣描述的: > 分類決策樹模型是一種描述對例項進行分類的樹形結構,決策樹由節點(node)和有向邊(directed edge)組成。節點有兩種型別:**內部節點**(iternal node)和**葉節點**(leaf node)。內部節點表示一個特徵或屬性,葉節點表示一個類。 上述提到的內部節點可以理解成樣本的屬性特徵,而葉節點可以理解成樣本的標籤,而有向邊可以理解成不同的屬性特徵結果。一般我們在繪製決策樹的時候,內部節點用方框或長方形表示,而葉節點用圓形或橢圓表示。(**注意:這個並不是絕對的,在不同資料中可能有不同的表示方法,比如《統計學習方法》一書中用圓表示內部節點,用方形表示葉子節點,而在《機器學習實戰》一書中表示方式正好相反**) 枯燥的文字說明總是會降低讀者的閱讀慾望,下面我們不妨通過一個實際的例子來說明下,從而加強讀者對決策樹的理解。 比如說,形容女生美與醜的時候一般會存在多個指標,這個例子感覺有點危險,還是換個吧。 **例子來源:李航——《統計學習方法》(第二版)** 比如說,我們沒Money用了,想要去銀行貸款,這個時候銀行就會根據你自己的個人附帶特徵來決定是否給你放款。假設這裡的屬性特徵有四個,分別是年紀、是否工作、是否有房子、信用情況,這些屬性特徵就相當於是**內部節點**,標籤(結果)是否放款相當於**葉子節點**,而不同屬性特徵的結果表示有向邊,像年紀中有青年、中年、老年,信用情況有好、一般、非常好等表示不同的有向邊。 對此,我們可以根據自己的感覺來**手動繪製**一個簡單的決策樹模型:
我們知道,上述決策樹僅僅是我們自己手動來實現的,不一定能夠運用於解決實際問題。而決策樹的任務,則是根據已有的資料樣本集訓練得到這麼一顆樹形結構模型,以此來對未知分類的資料進行類別預測。對此,我們要向得到這麼一顆**儘可能理想**的決策樹,則不得不考慮以下幾個問題: * 決策樹的指標(屬性特徵)選擇的順序應該是怎樣的的?哪個特徵應當被優先考慮呢? * 如果構建出的決策樹出現了過擬合問題,也就說我們的訓練的時候還不錯,但是一測試就GG,這個時候我們應當怎麼解決呢? 本篇文章,主要內容是屬性特徵的優先選取問題。 ## 二、屬性特徵的選擇 對於屬性特徵的選擇,我們應當優先選取對訓練資料集具有明顯分類能力的特徵,這樣可以提高我們決策樹的學習效率。假如說一個屬性特徵的分類結果與隨機分類基本沒什麼差別,則我們可以說這個屬性特徵基本是沒有分類能力的。 比如說,我們這裡有12個關於女生美與醜的資料樣本,其中六個是醜女,另外六個是美女,六個醜女身高有三個是165cm、三個是185cm,而另外六個美女身高同樣如此,這樣的話,我們僅僅通過身高來對女生美貌的判斷基本是沒有分類能力的。(**僅僅是個例子,不代表任何觀點**) 所以,我們理想情況下決策樹的生成理應是這樣的:**隨著決策過程的不斷進行,我們希望決策樹的分支節點所包含的樣本儘可能的屬於同一類別(標籤相同),也就是節點的“純度”越來越高。** 所以,**決策樹的關鍵技術在於屬性特徵的選擇。**對於屬性特徵的選擇,我們通常有三個準則:**資訊增益、資訊增益比(增益率)和基尼指數。** ### 2.1 資訊增益 上面提到了樣本濃度,比如說我這裡有10個女生,10個都是美女,那就說此時的樣本濃度高,假如美女和醜女五五分,那這個時候的濃度就比較低了。這裡的“濃度”表達的就是這個意思,**它主要針對的是標籤(結果)**。 而表示樣本“濃度”的指標,最常用的就是**“資訊熵”**了。假定當前樣本集合$D$中第$k$類(總共$n$類)樣本所佔的**比例**為$p_k$,則此時樣本$D$的資訊熵為: $$ Ent(D) = -\sum_{k=1}^np_klog_2(p_k) \tag{2-1} $$ 通過上述公式,我們可以知道10個美女(一個類別)的資訊熵為 $$ Ent(D)=-1 * log_21=0 $$ 美女丑女五五分(兩類)的資訊熵為: $$ Ent(D) = -\frac{1}{2}log_2\frac{1}{2}-\frac{1}{2}log_2\frac{1}{2}=1 $$ 通過上面資訊熵的簡單計算,我們可以知道,**資訊熵的值越小,則純度越高。** 既然我們已經瞭解了資訊增益的計算公式及其所表達的意義,那麼對於一個數據樣本集,我們應當如何用程式碼來進行計算呢?下面我們來試試吧。 本次使用到的資料樣本來自 李航——《統計學習方法》(第二版),資料是關於貸款申請的,具體如下: ![](https://gitee.com/tianxingjian123/my-images-repository/raw/master/img/jueceshu_2.jpg) 那麼現在我們來通過程式碼形式計算下這個資料樣本集的資訊熵吧: 首先建立一個`establish_data`方法來建立一個二維陣列用於儲存上述資料樣本集的相關資訊(關於屬性特徵所對於的值0,1,2之類的,大家可以參考上述表格對號入座,這裡就不做過多解釋了): ``` """ Author: Taoye 微信公眾號: 玩世不恭的Coder Explain:建立訓資料集 """ def establish_data(): data = [[0, 0, 0, 0, 'N'], # 樣本資料集相關資訊,前面幾項代表屬性特徵,最後一項表示是否放款 [0, 0, 0, 1, 'N'], [0, 1, 0, 1, 'Y'], [0, 1, 1, 0, 'Y'], [0, 0, 0, 0, 'N'], [1, 0, 0, 0, 'N'], [1, 0, 0, 1, 'N'], [1, 1, 1, 1, 'Y'], [1, 0, 1, 2, 'Y'], [1, 0, 1, 2, 'Y'], [2, 0, 1, 2, 'Y'], [2, 0, 1, 1, 'Y'], [2, 1, 0, 1, 'Y'], [2, 1, 0, 2, 'Y'], [2, 0, 0, 0, 'N']] return np.array(data) ``` 隨後,我們建立一個`calc_information_entropy`方法用於計算資訊熵,計算過程的程式碼可結合上述的公式來看。另外,需要說一點的是,為了方便對放款結果進行分類,我們使用`pandas`包進行處理,關於`pandas`的使用,大夥可以參考文件,Taoye後期也會整理一份。當然了,不用`pandas`模組也能實現這個功能,有興趣的讀者可自行嘗試,也不難。`calc_information_entropy`具體程式碼如下: ``` """ Author: Taoye 微信公眾號: 玩世不恭的Coder Explain:計算資訊熵 """ def calc_information_entropy(data): data_number, _ = data.shape information_entropy = 0 for item in pd.DataFrame(data).groupby(_ - 1): print(item[1]) proportion = item[1].shape[0] / data_number information_entropy += - proportion * np.log2(proportion) return information_entropy ``` 我們執行上述程式碼,來看看具體的資訊熵結果:
相比大家都瞭解了資訊熵的概念,並能夠手動計算樣本集的資訊熵了,現在我們再來把資訊增益搬出來吧。 假設一個屬性特徵$a$有$V$個可能的取值$\{a^1, a^2,.., a^V\}$,若使用$a$來對樣本集$D$進行劃分,這樣的話就會產生$V$個分支節點,其中第$v$個 分支節點包含了$D$中所有在屬性$a$上取值為$a^V$的樣本,記為$D^V$。於是可計算出用屬性特徵$a$對樣本集$D$進行劃分所獲得的**“資訊增益”**(information gain)為: $$ Gain(D, a)=Ent(D)-\sum_{v=1}^V\frac{D^v}{D}Ent(D^v) \tag{2-2} $$ 以上是周志華——《機器學習》一書中對資訊增益的相關說明。 枯燥的文字說明總是會降低讀者的閱讀慾望,上述符號也是有點多,我們不妨拿上面的貸款資料來進一步理解下上述資訊增益的內容: 我們單獨拿年齡這一個屬性特徵來計算其資訊增益吧,其有青年、中年、老年三個可能的值,也就是說上述的$a=年齡$,$\{a^1,a^2,...,a^V\}=\{青年,中年,老年\}$,而資料樣本集$D$為上述15個數據樣本,由於年齡有三個可能的值,所以此時會產生三個分支,即$V=3$。之前我們已經計算得到$Ent(D)=0.971$,現在我們只要計算出後一項$\sum_{v=1}^V\frac{D^v}{D}Ent(D^v)$的值即可得到該屬性特徵所對應的**資訊增益**: 通過資料,我們觀察得到如下資訊: * 對於年齡這個屬性特徵來講,青年、中年、老年分別有5個。 * 5個青年中有2個允許貸款,有三個不允許貸款;中年中有3個允許貸款,2個不允許貸款;老年中有4個允許貸款,有1個不允許貸款。 對此,我們可以計算: $$ \begin{aligned} \sum_{v=1}^V\frac{D^v}{D}Ent(D^v) & = \frac{5}{15}(-\frac{2}{5}log_2\frac{2}{5}-\frac{3}{5}log_2\frac{3}{5})\\ & +\frac{5}{15}(-\frac{3}{5}log_2\frac{3}{5}-\frac{2}{5}log_2\frac{2}{5}) \\ & +\frac{5}{15}(-\frac{4}{5}log_2\frac{4}{5}-\frac{1}{5}log_2\frac{1}{5}) \\ & = 0.883 \end{aligned} $$ 對此,我們的計算處年齡這個屬性特徵所對應的資訊增益值為: $$ Gain(D, 年齡) = 0.971-0.883=0.083 $$ 我們可以把後一項的內容理解成條件概率。另外,**資訊增益越大,則其所對應的屬性特徵的分類能力也就越強,也就是我們應當優先選取的特徵。** 同理,我們可以計算出工作、房子、信用屬性特徵所對應的資訊增益: $$ \begin{aligned} & Gain(D, 工作)=0.324 \\ & Gain(D, 房子)=0.420 \\ & Gain(D, 信用)=0.363 \end{aligned} $$ 我們比較哥哥屬性特徵的資訊增益值,可以發現**房子這個屬性特徵最大**,所以它應該是我們優先選擇的屬性特徵。 瞭解了資訊增益的計算及其意義,下面我們來通過程式碼計算一下(程式碼含義見註釋): ``` import numpy as np import pandas as pd np.__version__ pd.__version__ """ Author: Taoye 微信公眾號: 玩世不恭的Coder Explain:建立訓資料集 """ def establish_data(): data = [[0, 0, 0, 0, 'N'], # 樣本資料集相關資訊,前面幾項代表屬性特徵,最後一項表示是否放款 [0, 0, 0, 1, 'N'], [0, 1, 0, 1, 'Y'], [0, 1, 1, 0, 'Y'], [0, 0, 0, 0, 'N'], [1, 0, 0, 0, 'N'], [1, 0, 0, 1, 'N'], [1, 1, 1, 1, 'Y'], [1, 0, 1, 2, 'Y'], [1, 0, 1, 2, 'Y'], [2, 0, 1, 2, 'Y'], [2, 0, 1, 1, 'Y'], [2, 1, 0, 1, 'Y'], [2, 1, 0, 2, 'Y'], [2, 0, 0, 0, 'N']] return np.array(data) """ Author: Taoye 微信公眾號: 玩世不恭的Coder Explain:計算資訊熵 """ def calc_information_entropy(data): data_number, _ = data.shape information_entropy = 0 for item in pd.DataFrame(data).groupby(_ - 1): proportion = item[1].shape[0] / data_number information_entropy += - proportion * np.log2(proportion) return information_entropy """ Author: Taoye 微信公眾號: 玩世不恭的Coder Explain:找出對應屬性特徵值的樣本,比如找出所有年紀為青年的樣本資料集 """ def handle_data(data, axis, value): result_data = list() for item in data: if item[axis] == value: result_data.append(item) return result_data """ Author: Taoye 微信公眾號: 玩世不恭的Coder Explain:計算最大的資訊增益,並輸出其所對應的特徵索引 """ def calc_information_gain(data): feature_number = data.shape[1] - 1 # 屬性特徵的數量 base_entropy = calc_information_entropy(data) # 計算總體資料集的資訊熵 max_information_gain, best_feature = 0.0, -1 # 初始化最大資訊增益和對應的特徵索引 for index in range(feature_number): feat_list = [item[index] for item in data] feat_set = set(feat_list) new_entropy = 0.0 for set_item in feat_set: # 計算屬性特徵劃分後的資訊增益 sub_data = handle_data(data, index, set_item) proportion = len(sub_data) / float(data.shape[0]) # 計運算元集的比例 new_entropy += proportion * calc_information_entropy(np.array(sub_data)) temp_information_gain = base_entropy - new_entropy # 計算資訊增益 print("第%d個屬性特徵所對應的的增益為%.3f" % (index + 1, temp_information_gain)) # 輸出每個特徵的資訊增益 if (temp_information_gain >
max_information_gain): max_information_gain, best_feature = temp_information_gain, index # 更新資訊增益,確定的最大的資訊增益對應的索引 return best_feature if __name__ == "__main__": data = establish_data() print("屬性特徵對應的最大的資訊增益對應的索引為:%d" % calc_information_gain(data)) ``` 執行上述程式碼,可見輸出的各個屬性特徵的資訊增益,以及最大資訊增益對應的特徵索引: ![](https://gitee.com/tianxingjian123/my-images-repository/raw/master/img/jueceshu_4.png) 可以發現,和我們手動計算的如出一轍,所以此時我們應當優先選取索引為2的屬性特徵作為決策標準,也就是房子。 ### 2.2 資訊增益比(增益率) 我們使用資訊增益作為選取特徵指標的時候,存在偏向於選擇取值較多的特徵的問題。 比如我們將id作為上述資料集的一個分類屬性,通過計算可以發現該資訊增益最大,但實際上該id對類別不具有什麼分類能力,所以這樣得到的決策樹不具有泛化能力,無法對新樣本進行有效預測。 為了解決資訊增益存在的這個問題,我們就引入了資訊增益比(增益率)的概念,著名的C4.5演算法就是用“增益率”來作為選取最優劃分屬性。增益率定義為: $$ Gain_ratio(D, a)=\frac{Gain(D, a)}{IV(a)} \tag{2-3} $$ $$ 其中,IV(a)=-\sum_{v=1}^V\frac{|D^v|}{|D|}log_2\frac{|D^v|}{|D|} \tag{2-4} $$ $IV(a)$稱為$a$的“固有值”(intrinsic value)。通常$a$的取值數目越多,則$IV(a)$的值會越大。其中的$a$的取值比如說:上述的年紀有青年、中年、老年三種取值。 對於上述的貸款資料集來說,信用情況有一般、好和非常好三種,比例分為是$\frac{5}{15}、\frac{6}{15}、\frac{4}{15}$。毒刺,我們可以計算信用情況的“固有值”: $$ \begin{aligned} IV(信用) & =-\sum_{v=1}^V\frac{|D^v|}{|D|}log_2\frac{|D^v|}{|D|} \\ & =-\frac{5}{15}log_2\frac{5}{15}-\frac{6}{15}log_2\frac{6}{15}-\frac{4}{15}log_2\frac{4}{15} \\ & = 1.566 \end{aligned} $$ 所以,對於信用屬性來講,其增益率為: $$ \begin{aligned} Gain\_ratio(D, 信用) & =\frac{Gain(D, 信用)}{IV(信用)} \\ & = \frac{0.363}{1.566} \\ & = 0.232 \end{aligned} $$ 同理,我們可以計算出其他屬性特徵的增益率: $$ \begin{aligned} Gain\_ratio(D, 年齡) & =0.052 \\ Gain\_ratio(D, 工作) & =0.352 \\ Gain\_ratio(D, 房子) & =0.433 \\ \end{aligned} $$ 計算增益率的具體程式碼可參考如下: ``` """ Author: Taoye 微信公眾號: 玩世不恭的Coder Explain:計算增益率 """ def calc_gain_ratio(data): feature_number = data.shape[1] - 1 # 屬性特徵的數量 base_entropy = calc_information_entropy(data) # 計算總體資料集的資訊熵 for index in range(feature_number): feat_list = [item[index] for item in data] feat_set = set(feat_list) new_entropy, iv = 0.0, 0.0 for set_item in feat_set: # 計算屬性特徵劃分後的資訊增益 sub_data = handle_data(data, index, set_item) proportion = len(sub_data) / float(data.shape[0]) # 計運算元集的比例 new_entropy += proportion * calc_information_entropy(np.array(sub_data)) iv += -proportion * np.log2(proportion) temp_information_gain = base_entropy - new_entropy # 計算資訊增益 gain_ratio = temp_information_gain / iv print("第%d個屬性特徵所對應的增益率為%.3f,資訊增益為%.3f" % (index + 1, gain_ratio, temp_information_gain)) # 輸出每個特徵的資訊增益 ``` 執行結果如下: ![](https://gitee.com/tianxingjian123/my-images-repository/raw/master/img/jueceshu_5.jpg) 在C4.5演算法中,並不是直接單一的使用增益率來對屬性特徵的選取進行決策,而是**先在資訊增益中選取高於平均水平的屬性作為候選,然後從候選中選取增益率最高的。** 關於C4.5演算法,我們後期會講到。 ### 2.3 基尼指數 基尼指數是另外一種選取屬性的指標。 前面我們提到了,資訊熵是描述資料樣本純度一個標準,而在基尼指數中的基尼值同樣可以體現資料樣本的純度。資料樣本集$D$的基尼值可以用$Gini(D)$來表示(其中$k$表示有$k$個標籤結果): $$ Gini(D)=1-\sum_{k=1}^{|y|}p_k^2 \tag{2-5} $$ 基尼值$Gini(D)$越小,說明資料樣本純度越高。而屬性$a$對應的基尼指數$Gini\_index(D,a)$可以定義為: $$ Gini\_index(D, a)=\sum_{v=1}^V\frac{|D^v|}{|D|}Gini(D^v) \tag{2-6} $$ 我們同樣來分別計算下上述貸款資料集的基尼指數。 對於信用情況這一屬性特徵來講,其基尼指數的手動計算過程如下所示: $$ \begin{aligned} Gini\_index(D, 信用) & = \sum_{v=1}^{V}\frac{|D^v|}{|D|}Gini(D^v) \\ & = \frac{5}{15}(1-(\frac{4}{5})^2 - (\frac{1}{5})^2)+\frac{6}{15}(1-(\frac{2}{6})^2 - (\frac{4}{6})^2)+\frac{4}{15}(1-(\frac{4}{4})^2 - (\frac{0}{4})^2) \\ & = \end{aligned} $$ 對於其他屬性的基尼指數,讀者可自行根據上述過程進行計算(真的很簡單)。關於基尼指數的計算程式碼,可參考如下: ``` """ Author: Taoye 微信公眾號: 玩世不恭的Coder Explain:計算基尼指數 """ def calc_gini_index(data): feature_number = data.shape[1] - 1 # 屬性特徵的數量 base_entropy = calc_information_entropy(data) # 計算總體資料集的資訊熵 for index in range(feature_number): feat_list = [item[index] for item in data] feat_set = set(feat_list) new_entropy, iv, gini_index = 0.0, 0.0, 0.0 for set_item in feat_set: # 計算屬性特徵劃分後的資訊增益 sub_data = handle_data(data, index, set_item) temp_df = pd.DataFrame(sub_data) yes_proportion = temp_df[temp_df[temp_df.shape[1]-1] == "Y"].shape[0] / len(sub_data) gini_value = 1 - (yes_proportion ** 2) - ((1- yes_proportion) ** 2) proportion = len(sub_data) / float(data.shape[0]) # 計運算元集的比例 new_entropy += proportion * calc_information_entropy(np.array(sub_data)) iv += -proportion * np.log2(proportion) gini_index += gini_value * proportion # 計算基尼指數 temp_information_gain = base_entropy - new_entropy # 計算資訊增益 gain_ratio = temp_information_gain / iv print("第%d個屬性特徵所對應的資訊增益為%.3f,增益率為%.3f, 基尼指數為%.3f" % (index + 1, temp_information_gain, gain_ratio, gini_index)) ``` 執行結果: ![](https://gitee.com/tianxingjian123/my-images-repository/raw/master/img/jueceshu_6.png) 以上就是基尼指數的計算及其相關程式碼,一般來講,基尼指數越小就優先被劃分。 上述內容的完整程式碼如下: ``` import numpy as np import pandas as pd np.__version__ pd.__version__ """ Author: Taoye 微信公眾號: 玩世不恭的Coder Explain:建立訓資料集 """ def establish_data(): data = [[0, 0, 0, 0, 'N'], # 樣本資料集相關資訊,前面幾項代表屬性特徵,最後一項表示是否放款 [0, 0, 0, 1, 'N'], [0, 1, 0, 1, 'Y'], [0, 1, 1, 0, 'Y'], [0, 0, 0, 0, 'N'], [1, 0, 0, 0, 'N'], [1, 0, 0, 1, 'N'], [1, 1, 1, 1, 'Y'], [1, 0, 1, 2, 'Y'], [1, 0, 1, 2, 'Y'], [2, 0, 1, 2, 'Y'], [2, 0, 1, 1, 'Y'], [2, 1, 0, 1, 'Y'], [2, 1, 0, 2, 'Y'], [2, 0, 0, 0, 'N']] return np.array(data) """ Author: Taoye 微信公眾號: 玩世不恭的Coder Explain:計算資訊熵 """ def calc_information_entropy(data): data_number, _ = data.shape information_entropy = 0 for item in pd.DataFrame(data).groupby(_ - 1): proportion = item[1].shape[0] / data_number information_entropy += - proportion * np.log2(proportion) return information_entropy """ Author: Taoye 微信公眾號: 玩世不恭的Coder Explain:找出對應屬性特徵值的樣本,比如找出所有年紀為青年的樣本資料集 """ def handle_data(data, axis, value): result_data = list() for item in data: if item[axis] == value: result_data.append(item) return result_data """ Author: Taoye 微信公眾號: 玩世不恭的Coder Explain:計算最大的資訊增益,並輸出其所對應的特徵索引 """ def calc_information_gain(data): feature_number = data.shape[1] - 1 # 屬性特徵的數量 base_entropy = calc_information_entropy(data) # 計算總體資料集的資訊熵 max_information_gain, best_feature = 0.0, -1 # 初始化最大資訊增益和對應的特徵索引 for index in range(feature_number): feat_list = [item[index] for item in data] feat_set = set(feat_list) new_entropy = 0.0 for set_item in feat_set: # 計算屬性特徵劃分後的資訊增益 sub_data = handle_data(data, index, set_item) proportion = len(sub_data) / float(data.shape[0]) # 計運算元集的比例 new_entropy += proportion * calc_information_entropy(np.array(sub_data)) temp_information_gain = base_entropy - new_entropy # 計算資訊增益 print("第%d個屬性特徵所對應的的增益為%.3f" % (index + 1, temp_information_gain)) # 輸出每個特徵的資訊增益 if (temp_information_gain > max_information_gain): max_information_gain, best_feature = temp_information_gain, index # 更新資訊增益,確定的最大的資訊增益對應的索引 return best_feature """ Author: Taoye 微信公眾號: 玩世不恭的Coder Explain:計算增益率 """ def calc_gain_ratio(data): feature_number = data.shape[1] - 1 # 屬性特徵的數量 base_entropy = calc_information_entropy(data) # 計算總體資料集的資訊熵 for index in range(feature_number): feat_list = [item[index] for item in data] feat_set = set(feat_list) new_entropy, iv = 0.0, 0.0 for set_item in feat_set: # 計算屬性特徵劃分後的資訊增益 sub_data = handle_data(data, index, set_item) proportion = len(sub_data) / float(data.shape[0]) # 計運算元集的比例 new_entropy += proportion * calc_information_entropy(np.array(sub_data)) iv += -proportion * np.log2(proportion) temp_information_gain = base_entropy - new_entropy # 計算資訊增益 gain_ratio = temp_information_gain / iv print("第%d個屬性特徵所對應的增益率為%.3f,資訊增益為%.3f" % (index + 1, gain_ratio, temp_information_gain)) # 輸出每個特徵的資訊增益 """ Author: Taoye 微信公眾號: 玩世不恭的Coder Explain:計算基尼指數 """ def calc_gini_index(data): feature_number = data.shape[1] - 1 # 屬性特徵的數量 base_entropy = calc_information_entropy(data) # 計算總體資料集的資訊熵 for index in range(feature_number): feat_list = [item[index] for item in data] feat_set = set(feat_list) new_entropy, iv, gini_index = 0.0, 0.0, 0.0 for set_item in feat_set: # 計算屬性特徵劃分後的資訊增益 sub_data = handle_data(data, index, set_item) temp_df = pd.DataFrame(sub_data) yes_proportion = temp_df[temp_df[temp_df.shape[1]-1] == "Y"].shape[0] / len(sub_data) gini_value = 1 - (yes_proportion ** 2) - ((1- yes_proportion) ** 2) proportion = len(sub_data) / float(data.shape[0]) # 計運算元集的比例 new_entropy += proportion * calc_information_entropy(np.array(sub_data)) iv += -proportion * np.log2(proportion) gini_index += gini_value * proportion temp_information_gain = base_entropy - new_entropy # 計算資訊增益 gain_ratio = temp_information_gain / iv print("第%d個屬性特徵所對應的資訊增益為%.3f,增益率為%.3f, 基尼指數為%.3f" % (index + 1, temp_information_gain, gain_ratio, gini_index)) if __name__ == "__main__": data = establish_data() calc_gini_index(data) ``` 優先選取屬性特徵的指標主要有三個,分別是資訊增益、增益率、基尼指數。對上述內容做個簡單的總結吧: * 屬性特徵的資訊增益越高,**按道理來講**應當被優先選取,常用於**$ID3$演算法** * 屬性特徵的增益率越高,**按道理來講**應當被優先選取,常用與**$C4.5$演算法** * 屬性特徵的尼基指數低,**按道理來講**應當被優先選取,常用於**$CART$演算法** 本文主要是決策樹的理論部分內容,介紹了什麼決策樹,以及生成決策樹時所需要優先選取的三種決策標準。有學習的過SVM,或閱讀過Taoye之前寫的幾篇SVM內容的文章可以發現,決策樹相對於SVM來講要簡單很多,沒有太多且複雜的公式推導。關於決策樹的其他內容,比如決策樹的生成、視覺化、剪枝等,我們放在後面幾篇文章來寫。 我是Taoye,愛專研,愛分享,熱衷於各種技術,學習之餘喜歡下象棋、聽音樂、聊動漫,希望藉此一畝三分地記錄自己的成長過程以及生活點滴,也希望能結實更多志同道合的圈內朋友,更多內容歡迎來訪微信公主號:**玩世不恭的Co