機器學習實戰(第三篇)-決策樹構造
首先我們分析下決策樹的優點和缺點。優點:計算複雜度不高,輸出結果易於理解,對中間值的卻是不敏感,可以處理不相關特徵資料;缺點:可能會產生過度匹配問題。適用資料型別:數值型和標稱型。
本篇文章我們將一步步地構造決策樹演算法,並會涉及許多有趣的細節。首先我們先討論數學上如何使用資訊理論劃分資料集,然後編寫將理論應用到具體的資料集上,最後編寫程式碼構建決策樹。
在構造決策樹時,我們需要解決的第一個問題就是,當前資料集上哪個特徵在劃分資料分類時起決定性作用。為了找到決定性的特徵,劃分出最好的結果,我們必須評估每個特徵。完成測試之後,原始資料集就被劃分為幾個資料子集了。這些資料子集會分佈在第一個決策點的所有分支上。如果某個分支下的資料屬於同一型別,則當前無需閱讀的垃圾郵件已經正確地劃分資料分類,無需進一步對資料集進行分割。如果資料子集內的資料不屬於同一型別,則需要重複劃分資料子集的過程。如何劃分資料子集的演算法和劃分原始資料集的方法相同,知道所有具有相同型別的資料均在一個數據子集內。
建立分支的虛擬碼函式createBranch()如下所示:
檢測資料集中每個子項是否屬於同一個分類:
IF so return 類標籤;
ELSE
尋找劃分資料集的最好特徵
劃分資料集
建立分支節點
for 每個劃分的子集
呼叫函式createBranch()並增加返回結果到分支節點中
return 分支節點
上面的虛擬碼createBranch是一個遞迴函式,在倒數第二行直接呼叫了它自己。後面我們將上面的虛擬碼轉換為Python程式碼,這裡我們需要了解演算法是如何劃分資料集的。
決策樹的一般流程
(1)收集資料:可以使用任何方法;
(2)準備資料:樹構造演算法只適用於標稱型資料,因此數值型資料必須離散化;
(3)分析資料:可以使用任何方法,構造樹完成後,我們應該檢查圖形是否符合預期;
(4)訓練演算法:構造樹的資料結構;
(5)測試演算法:使用經驗樹計算錯誤率
(6)使用演算法:此步驟可以適用於任何監督學習演算法,而使用決策樹可以更好地理解資料的內在含義。
一些決策樹演算法採用二分法劃分資料。如果依據某個屬性劃分資料將會產生四個可能的值,我們把資料劃分成四塊,並建立四個不同的分支。本章我們將使用ID3演算法劃分資料集,該演算法處理如何劃分資料集,何時停止劃分資料集。每次劃分資料集時我們只選取一個特徵屬性,如果訓練集中存在20個特徵,第一次我們選取哪個特徵作為劃分的參考屬性呢?
下表中包含了5個海洋動物,特徵包括:不浮出水面是否可以生存,以及是否有腳蹼。我們可以將這些動物劃分為兩類:魚類和非魚類。現在我們想要決定依據第一個特徵還是第二個特徵劃分資料。在回答這個問題之前,我們必須採用量化的方法判斷如何劃分資料。
編號 | 不浮出水面是否可以生存 | 是否有腳蹼 | 屬於魚類 |
---|---|---|---|
1 | 是 | 是 | 是 |
2 | 是 | 是 | 是 |
3 | 是 | 否 | 否 |
4 | 否 | 是 | 否 |
5 | 否 | 是 | 否 |
劃分資料集的最大原則是:將無序的資料變得更加有序。我們可以使用多種方法劃分資料集,但是每種演算法都有各自的優缺點。組織雜亂無章資料的另一種方法就是使用資訊理論度量資訊,資訊理論是量化處理資訊的分支科學。我們可以在劃分資料之前使用資訊理論量化度量資訊的內容。
在劃分資料集之前之後資訊發生的變化成為資訊增益,知道如何計算資訊增益,我們就可以計算每個特徵值劃分資料集獲得的資訊增益,獲得資訊增益最高的特徵就是最好的選擇。在可以評測哪種資料劃分方式是最好的資料劃分之前,我們必須先學習計算資訊增益。集合資訊的度量方式成為夏農熵或稱為熵。如果看不明白什麼是資訊增益(information gain)和熵(entropy)請不要著急。熵定義為資訊的期望值,在明確這個概念之前,我們必須知道資訊的定義。如果待分類的事務可能劃分在多個分類中,則符號xi 的資訊定義為:
其中p(xi)是選擇該分類的概率,為了計算熵,我們需要計算所有類別所有可能包含的資訊的期望值,通過下面的公式得到:
其中n是分類的數目。
下面我們將學習如何使用Python計算資訊熵,建立名為tree.py的檔案,輸入下面的程式碼內容,下面程式碼的功能就是計算資訊熵:
from math import log
def calcShannonEnt(dataSet):
numEntries=len(dataSet)
labelCounts={}
for featVec in dataSet:
currentLabel=featVec[-1]
if currentLabel not in labelCounts.keys():
labelCounts[currentLabel]=0
labelCounts[currentLabel]+=1
shannonEnt=0.0
for key in labelCounts:
prob=float(labelCounts[key])/numEntries
shannonEnt=prob*log(prob,2)
return shannonEnt
上面的程式非常簡單。首先,計算資料集中例項的總數,我們也可以在需要時再計算這個值,但是由於程式碼中多次用到這個值,為了提高程式碼效率,我們顯示的申明一個變數儲存例項總數。然後,建立一個數據字典,它的鍵值是最後一列的數值。如果當前鍵值不存在,則擴充套件字典並將其加入當前字典。每個鍵值都記錄了當前類別出現的次數。最後,我們所用類標籤發生頻率計算出類別出現的概率。我們將用這個概率計算夏農熵,統計所有類標籤發生的次數。下面我們看如何使用熵劃分資料集。
在tree.py檔案中,我們可以利用creatDataSet()函式得到上表中的簡單魚鑑定資料集,你可以輸入自己的createDataSet()函式:
def createDataSet():
dataSet=[[1,1,'yes'],[1,1,'yes'],[1,0,'no'],[1,1,'yes'],[0,1,'no'],[0,1,'no']]
labels=['no surfacing','flippers']
return dataSet,labels
在Python命令列中輸入下列命令:
熵越高,則混合的資料也越多,我們可以在資料集中新增更多的分類,觀察熵是如何變化的,這我們增加第三個名為maybe的分類,測試熵的變化:
得到熵之後,我們就可以按照最大資訊增益的方法劃分資料集,下一節