1. 程式人生 > >機器學習筆記:ID3演算法建立決策樹(二)

機器學習筆記:ID3演算法建立決策樹(二)

在《機器學習筆記: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)減去條件熵
拆分子集:對作為根節點的屬性的資料根據不同的值分成子集。
對剩餘屬性重複上述步驟。

這是個人理解,如果有不到位的地方,或者有理解偏差,希望有人能指出扶正,交流學習。