機器學習筆記:ID3演算法建立決策樹(二)
阿新 • • 發佈:2019-02-20
在《機器學習筆記:ID3演算法建立決策樹(一)》中記錄了ID3演算法的計算公式和步驟,現在用例子記錄一下ID3構建決策樹的過程。
對以下資料進行分類:
- | 是否能飛? | 是否有羽毛? | 是小鳥? |
---|---|---|---|
1 | 是 | 是 | 是 |
2 | 是 | 是 | 是 |
3 | 是 | 否 | 否 |
4 | 否 | 是 | 否 |
5 | 是 | 否 | 是 |
是否能飛用0,1表示,0不能飛,1能飛;
是否有羽毛用0,1表示,0沒有羽毛,1有羽毛;
也就是用是否能飛,是否有羽毛去判斷一個東西是不是小鳥。
用矩陣表達如下:
def createDataSet ():
dataSet = [[1,1,'是'],
[1,1,'是'],
[1,0,'否'],
[0,1,'否'],
[0,1,'否']]
labels = ['能飛的','有羽毛的']
return dataSet, labels
根據熵公式計算熵:
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 * math.log(prob,2 )
return shannonEnt
對整個樣本資料按類別劃分子集:
def splitDataSet(dataSet,axis,value):
retDataSet = []
for featVec in dataSet:
if featVec[axis] == value:
#featVec 是一維陣列,下標為axis元素之前的值加入到reducedFeatVec
reducedFeatVec = featVec[:axis]
#下一行的內容axis+1之後的元素加入到reducedFeatVec
reducedFeatVec.extend(featVec[axis+1:])
retDataSet.append(reducedFeatVec)
return retDataSet
選擇資訊增益最大的維度(列,也可以理解為屬性)作為決策樹的根節點
def chooseBestFeatureToSplit(dataSet):
numFeatures = len(dataSet[0]) - 1
baseEntropy = calcShannonEnt(dataSet)
bestInfoGain = 0.0
bestFeature = -1
for i in range(numFeatures):
featList = [example[i] for example in dataSet]
uniqueVals = set(featList) #值去重
newEntropy = 0.0
for value in uniqueVals:
#有多少個值就有多少個維度
subDataSet = splitDataSet(dataSet, i, value)
prob = len(subDataSet)/float(len(dataSet))
newEntropy += prob * calcShannonEnt(subDataSet)
infoGain = baseEntropy - newEntropy
if (infoGain > bestInfoGain):
bestInfoGain = infoGain
bestFeature = i
return bestFeature
統計每個維(列,或者理解為屬性)下的各個值出現的次數,用字典儲存:
def majorityCnt(classList):
classCount={}
for vote in classList:
if vote not in classCount.keys(): classCount[vote] = 0
classCount[vote] += 1
sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True)
return sortedClassCount[0][0]
建立樹:
def createTree(dataSet,labels):
classList = [example[-1] for example in dataSet]
if classList.count(classList[0]) == len(classList):
return classList[0] #當所有型別都相同時 返回這個型別
if len(dataSet[0]) == 1: #當沒有可以在分類的特徵集時
return majorityCnt(classList)
bestFeat = chooseBestFeatureToSplit(dataSet)
bestFeatLabel = labels[bestFeat]
myTree = {bestFeatLabel:{}}
del(labels[bestFeat])
featValues = [example[bestFeat] for example in dataSet]
uniqueVals = set(featValues)
for value in uniqueVals:
subLabels = labels[:]
#對每個特徵集遞迴呼叫建樹方法
myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value),subLabels)
return myTree
呼叫
myDat,labels = createDataSet()
print(createTree(myDat, labels))
結果
{'能飛的': {0: '否', 1: {'有羽毛的': {0: '否', 1: '是'}}}}
接下來繼續學習圖形化顯示決策樹,更直觀。
總結
計算各屬性的資訊增益,找出最大者為根節點
先驗熵:樣板資料中,先求出各種值出現的概率P(ui),再利用公式求熵
後驗熵:對其他列,先求出各種值出現的概率P(vi),再求出先驗列中各種值對本列取值為vi時的概率P(u|vi),再根據公式求熵H(U|vi),把u為各種值的情況下的H(U|vi) 算出來
條件熵:對後驗熵在輸出符號集V中求期望,接收到全部符號後對信源的不確定性,根據後驗熵得到的P(vi)乘以H(U|vi)之和
資訊增益:先驗熵與條件熵的差,即先驗熵中求得的P(ui)減去條件熵
拆分子集:對作為根節點的屬性的資料根據不同的值分成子集。
對剩餘屬性重複上述步驟。
這是個人理解,如果有不到位的地方,或者有理解偏差,希望有人能指出扶正,交流學習。