爲了使決策樹最優,哪個屬性將在樹的根節點被測試?分類能力最好的屬性被選做樹的根結點的測試。採用不一樣測試屬性及其前後順序將會生成不一樣的決策樹。python
定義一個統計屬性,稱爲「信息增益」(information gain),用來衡量給定的屬性區分訓練樣例的能力。度量信息增益的標準爲「熵」(entropy)。信息量就是不肯定性的多少,熵越大,信息的不肯定性越大算法
熵表明一個系統的雜亂程度,熵越大,系統越雜亂。對一個數據集中數據的分類就是使得該數據集熵減少的過程。數據結構
決策樹算法就是一個劃分數據集的過程。劃分數據集的原則就是:將無序的數據變得更加有序。咱們假設獲得的數據是有用的信息,處理信息的一種有效的方法就是利用信息論。app
信息增益:劃分數據集先後信息的變化成爲信息增益,得到信息增益最高的特徵就是最好的選擇。那麼如何計算信息增益?集合信息的度量方式稱爲熵。函數
「 若是看不明白什麼是信息增益和熵,請不要着急——它們自誕生的那一天起,就註定會令世人十分費解。克勞德香農寫信息論以後,約翰馮諾依曼建議使用「熵」這個術語,由於你們都不知道它是什麼意思。 」測試
熵定義爲信息的指望值,在明晰這個概念以前,先來看看信息的定義。若是待分類的事務可能劃分在多個分類之中,則符號 的信息定義爲:spa
其中 是選擇該分類的機率。orm
全部類別全部可能值包含的信息指望值,便是計算所得的熵:事務
下表包含5個海洋動物,特徵包括:不浮出水面是否能夠生存,以及是否有腳蹼。將這些動物分爲兩類:魚類和非魚類。要研究的問題就是依據第一個特徵仍是第二個特徵劃分數據。ip
不浮出水面是否能夠生存 | 是否又腳蹼 | 屬於魚類 | |
1 | 是 | 是 | 是 |
2 | 是 | 是 | 是 |
3 | 是 | 否 | 否 |
4 | 否 | 是 | 否 |
5 | 否 | 是 | 否 |
先給出計算香農熵的python代碼,以備後續使用(一下全部代碼均是python寫的)
1 def calcShannonEnt(dataSet): 2 numEntries = len(dataSet) 3 labelCounts = {} 4 for featVec in dataSet: 5 currentLabel = featVec[-1] 6 if currentLabel not in labelCounts.keys(): labelCounts[currentLabel] = 0 7 labelCounts[currentLabel] += 1 8 shannonEnt = 0.0 9 for key in labelCounts: 10 prob = float(labelCounts[key])/numEntries 11 shannonEnt -= prob * log(prob, 2) 12 return shannonEnt
若是瞭解python,代碼仍是比較簡單的,不過要事先說明一下dataSet是什麼樣的數據,怎樣的數據結構。這就引出了下面的代碼,用來生成dataSet,這樣你就能更好地瞭解代碼中「currentLabel = featVec[-1]」是怎麼回事了。
1 def createDataSet(): 2 dataSet = [[1, 1, 'yes'], 3 [1, 1, 'yes'], 4 [1, 0, 'no'], 5 [0, 1, 'no'], 6 [0, 1, 'no']] 7 labels = ['no surfacing', 'flippers'] 8 return dataSet, labels
咱們所處理的數據是形如dataSet這樣的數據集,每一個數據是list類型,數據的最後一項是數據的標籤。看一下效果:
熵越高,說明數據的混合度越高,增長數據類別能夠觀察熵的變化。
接下來作些什麼?別忘了初衷:依據第一個特徵仍是第二個特徵劃分數據?這個問題的回答就在於哪一種特徵的劃分熵更小一些。咱們將對每一個特徵劃分數據集的結果計算一次信息熵,而後判斷按照哪一個特徵劃分數據集是最好的劃分方式。
首先編寫一個函數用於按照給定特徵劃分數據集:
1 def splitDataSet(dataSet, axis, value): 2 retDataSet = [] 3 for featVec in dataSet: 4 if featVec[axis] == value: 5 reducedFeatVec = featVec[:axis] 6 reducedFeatVec.extend(featVec[axis+1:]) 7 retDataSet.append(reducedFeatVec) 8 return retDataSet
代碼中使用了python中自帶的兩個方法:extend()、append(),這兩個方法功能相似,可是在處理多個列表時,這兩個方法是徹底不一樣的,這個你們就自行百度一下。代碼比較好理解,一會兒沒有理解也沒事,慢慢來,先看看運行的效果,感性認識一下吧:
最後一個函數就是用於對每一個特徵劃分數據集的結果計算一次信息熵,而後判斷按照哪一個特徵劃分數據集是最好的劃分方式:
1 def chooseBestFeatureToSplit(dataSet): 2 numFeatures = len(dataSet[0]) - 1 3 baseEntropy = calcShannonEnt(dataSet) 4 bestInfoGain = 0.0; bestFeature = -1 5 for i in range(numFeatures): 6 featList = [example[i] for example in dataSet] 7 uniqueVals = set(featList) 8 newEntropy = 0.0 9 for value in uniqueVals: 10 subDataSet = splitDataSet(dataSet, i, value) 11 prob = len(subDataSet) / float(len(dataSet)) 12 newEntropy += prob * calcShannonEnt(subDataSet) 13 infoGain = baseEntropy - newEntropy 14 if(infoGain > bestInfoGain): 15 bestInfoGain = infoGain 16 bestFeature = i 17 return bestFeature
看得出,按照第一個特徵劃分得到的是最好的劃分,熵最小。