徒手寫代碼之《機器學習實戰》-----決策樹算法(2)(使用決策樹預測隱形眼鏡類型)

使用決策樹預測隱形眼鏡類型

說明:

將數據集文件 ‘lenses.txt’ 放在當前文件夾

from math import log
import operator

熵的定義

"""
這部分是在用代碼計算香農熵公式,即用代碼寫公式並計算結果
"""
def calcShannonEnt(dataSet):
    #數據集行數
    numEntries = len(dataSet)
    #創建空字典記錄yes or no的次數
    labelCounts = {}
    #開始用循環語句統計標籤頻數,該思路和KNN算法是一樣的
    #the the number of unique elements and their occurance
    for featVec in dataSet:
        currentLabel = featVec[-1]
        if currentLabel not in labelCounts.keys(): 
            labelCounts[currentLabel] = 0
        labelCounts[currentLabel] += 1
    #初始值是0,然後根據公式,用循環語句開始計算
    shannonEnt = 0.0
    for key in labelCounts:
        #公式計算部分
        prob = float(labelCounts[key])/numEntries
        shannonEnt -= prob * log(prob, 2) 
    return shannonEnt


劃分數據集: 按照給定特徵劃分數據集

#這個函數後面用的上,先看懂代碼。後一個函數會讓你看懂它的真正作用。
def splitDataSet(dataSet, axis, value):
    retDataSet = []
    for featVec in dataSet:
        if featVec[axis] == value:
            #去掉axis特徵
            reducedFeatVec = featVec[:axis]     
            reducedFeatVec.extend(featVec[axis+1:])
            retDataSet.append(reducedFeatVec)
    return retDataSet

選擇最好的數據集劃分方式

#該函數選取最優的特徵,並返回最優特徵的索引值
def chooseBestFeatureToSplit(dataSet):
    #特徵數量
    #the last column is used for the labels
    numFeatures = len(dataSet[0]) - 1   
    #計算數據集的香農熵
    baseEntropy = calcShannonEnt(dataSet)
    #信息增益
    bestInfoGain = 0.0
    #最優特徵的索引值,-1是隨便設置的值,便於後續更新值
    bestFeature = -1
    #遍歷所有特徵
    for i in range(numFeatures):      
        #獲取dataSet的第i個所有特徵
        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)
        #信息增益。calculate the info gain; ie reduction in entropy
        infoGain = baseEntropy - newEntropy    
        #計算信息增益。compare this to the best gain so far
        if (infoGain > bestInfoGain):       
            #更新信息增益,找到最大的信息增益。if better than current best, set to best
            bestInfoGain = infoGain         
            #記錄信息增益最大的特徵的索引值
            bestFeature = i
    return bestFeature    

多數表決法決定該葉子節點的分類

#這個函數是在下一個函數裏面第二個停止條件時候用上的
"""
代碼與第2章classify0部分的投票表決代碼非常類似
"""
def majorityCnt(classList):
    classCount={}
    #統計classList中每個元素出現的次數
    for vote in classList:
        if vote not in classCount.keys(): 
            classCount[vote] = 0
        classCount[vote] += 1
    #最後利用operator操作鍵值排序字典,並返回出現次數最多的分類名稱
    sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
     #返回classList中出現次數最多的元素
    return sortedClassCount[0][0]

遞歸構建決策樹

#核心程序,創建樹
def createTree(dataSet, labels):
    #取出所有分類標籤,yes or no
    classList = [example[-1] for example in dataSet]
    #如果類別完全相同,則停止繼續劃分。這是第一個停止條件。
    if classList.count(classList[0]) == len(classList):
        return classList[0]
    #stop splitting when there are no more features in dataSe
    #如果特徵都遍歷完了,還是沒有劃分的很純淨,那麼就取數量多一點的那個類別。這是第二個停止條件
    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)
    #遍歷特徵,創建決策樹。
    """
    代碼遍歷當前選擇特徵包含的所有屬性值,在每個數據集劃分上遞歸調用函數,
    createTree(),得到的返回值將被插入到字典變量myTree中,因此函數終止執行時,字典中將會嵌套很多代表葉子節點信息的字典數據。
    """
    for value in uniqueVals:
        #copy all of labels, so trees don't mess up existing labels
        subLabels = labels[:]       
        myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value), subLabels)
    return myTree

使用決策樹執行分類


def classify(inputTree, featLabels, testVec):
    #獲取決策樹結點
    firstStr = list(inputTree)[0] 
    #下一個字典
    secondDict = inputTree[firstStr]  
    #返回節點特徵的索引值
    featIndex = featLabels.index(firstStr)                                               
   
    for key in secondDict.keys():
        if testVec[featIndex] == key:
            if type(secondDict[key]).__name__ == 'dict':
                classLabel = classify(secondDict[key], featLabels, testVec)
            else: 
                classLabel = secondDict[key]
    return classLabel

使用決策樹預測隱形眼鏡類型

#打開文本數據
fr = open('lenses.txt')
#解析數據
lenses = [inst.strip().split('\t') for inst in fr.readlines()]
lensesLabels = ['age', 'prescript', 'astigmatic', 'tearRate']
#訓練算法,根據creatTree函數建樹
lensesTree = createTree(lenses,lensesLabels)
print(lensesTree)

{'tearRate': {'reduced': 'no lenses', 'normal': {'astigmatic': {'yes': {'prescript': {'myope': 'hard', 'hyper': {'age': {'pre': 'no lenses', 'presbyopic': 'no lenses', 'young': 'hard'}}}}, 'no': {'age': {'pre': 'soft', 'presbyopic': {'prescript': {'myope': 'no lenses', 'hyper': 'soft'}}, 'young': 'soft'}}}}}}

使用決策樹模型進行預測

lensesLabels = ['age', 'prescript', 'astigmatic', 'tearRate']
classify(lensesTree, lensesLabels, lenses[0][:-1])
'no lenses'

對 lenses 數據集所有數據進行決策樹分類預測

preds = []
for i in range(len(lenses)):
    pred = classify(lensesTree, lensesLabels, lenses[i][:-1])
    preds.append(pred)
print(preds)
['no lenses', 'soft', 'no lenses', 'hard', 'no lenses', 'soft', 'no lenses', 'hard', 'no lenses', 'soft', 'no lenses', 'hard', 'no lenses', 'soft', 'no lenses', 'no lenses', 'no lenses', 'no lenses', 'no lenses', 'hard', 'no lenses', 'soft', 'no lenses', 'no lenses']
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章