1. 程式人生 > >決策樹 (一)

決策樹 (一)

# -*- coding: utf-8 -*-
"""
熵定義為資訊的期望值。
熵:表示隨機變數的不確定性。
條件熵:在一個條件下,隨機變數的不確定性。
資訊增益:熵 - 條件熵
在一個條件下,資訊不確定性減少的程度!
如果選擇一個特徵後,資訊增益最大(資訊不確定性減少的程度最大),那麼我們就選取這個特徵。
"""
from  math import log
"""
函式說明:建立測試集
Parameter:
    無
Returns:
    dataSet 資料集
    Labels  分類屬性
"""

def createDataSet():
    dataSet = [[0, 0, 0, 0, 'no'],         
            [0, 0, 0, 1, 'no'],
            [0, 1, 0, 1, 'yes'],
            [0, 1, 1, 0, 'yes'],
            [0, 0, 0, 0, 'no'],
            [1, 0, 0, 0, 'no'],
            [1, 0, 0, 1, 'no'],
            [1, 1, 1, 1, 'yes'],
            [1, 0, 1, 2, 'yes'],
            [1, 0, 1, 2, 'yes'],
            [2, 0, 1, 2, 'yes'],
            [2, 0, 1, 1, 'yes'],
            [2, 1, 0, 1, 'yes'],
            [2, 1, 0, 2, 'yes'],
            [2, 0, 0, 0, 'no']]
    Labels = ['不放貸', '放貸']
    return dataSet, Labels

"""
函式說明:計算給定資料集的經驗熵(夏農熵)
Parameters:
    dataSet 資料集
Returns:
    shannonEnt 經驗熵
"""
def calcShannonEnt(dataSet):
    #返回資料集的行數
    numEntirs = 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]) / numEntirs
        #
        shannonEnt -= prob * log(prob, 2)
    return shannonEnt

"""
函式說明:按照給定特徵劃分資料集
Parameters:
    dataSet 待劃分的資料集
    axis 劃分資料集的特徵
    value 需要返回的特徵值
Returns:
    retDataSet 返回的資料集列表
        
"""
def splitDataSet(dataSet, axis, value):
    #返回的資料集列表
    retDataSet = []
    for featVec in dataSet:
       if featVec[axis] == value:
            reducedFeatVec = featVec[:axis]
            #將符合條件的新增到返回的資料集
            reducedFeatVec.extend(featVec[axis+1 : ])
            retDataSet.append(reducedFeatVec)
    return retDataSet
        
"""
函式說明:選擇最優特徵
Paramaters:
    dataSet
Returns:
    beatFeature 資訊增益最優的特徵的索引值
"""
def chooseBestFeatureToSplit(dataSet):
    #特徵數量
    numFeatures = len(dataSet[0]) - 1
    #計算資料集的夏農熵
    baseEntropy = calcShannonEnt(dataSet)
    #資訊增益
    bestInfoGain = 0.0
    #最優特徵的索引值
    bestFeature = -1
    for i in range(numFeatures):
        #獲取dataSet的第i個所有特徵
        #將dataSet中的資料先按行依次放入example中,
        #然後取得example中的example[i]元素,放入列表featList中
        #相當於取所有行的第一個值
        #之所以這樣取,是因為dataSet是個列表,而不是矩陣,矩陣取第一列有方法
        featList = [ example[i] for example in dataSet]
        #建立集合set,元素不可重複
        uniqueVals = set(featList)
        #經驗條件熵
        newEntropy = 0.0
        #計算資訊增益
        for value in uniqueVals:
            #subDataSet是劃分後的子集
            subDataSet = splitDataSet(dataSet, i, value)
            #計運算元集的概率
            prob = len(subDataSet) / float(len(dataSet))
            #計算經驗條件熵
            newEntropy += prob * calcShannonEnt(subDataSet)
            
        #資訊增益
        infoGain = baseEntropy - newEntropy
        #列印每個特徵的資訊增益
        print("第%d個特徵的增益為:%.3f" % (i, infoGain))
        if (infoGain > bestInfoGain):
            bestInfoGain = infoGain
            bestFeature = i
    return bestFeature

if __name__ == '__main__':
    dataSet, features = createDataSet()
    print("最優特徵索引值:" + str(chooseBestFeatureToSplit(dataSet)))