機器學習之ID3決策樹python算法實現


​#本算法前提,要熟悉決策樹的理論知識,如:ID3算法流程,香農熵的計算公式和信息論原理

#數據集解釋  是否屬於魚類是目標標量

#把數據離散化,變成標量型 是--》1 否 --》0

#變成

#在設定2個標簽

#不浮出水面的魚類 no surfacing

#有腳蹼的魚類   flippers

#計算香農熵的方法 以二為底的對數  這里面的函數都是通用的

from math import log

import operator  #operator模塊輸出一系列對應Python內部操作符的函數

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 #記錄目標變量次數,出現一次就加1

shannonEnt = 0.0

for key in labelCounts:

prob = float(labelCounts[key])/numEntries   #計算概率

shannonEnt -= prob*log(prob,2)  #求熵,通過循環

return shannonEnt   #返回熵值

 

#創建數據集

def createDataSet():

dataSet = [[1,1,'yes'],

   [1,1,'yes'],

   [1,0,'no'],

   [0,1,'no'],

   [0,1,'no']]

labels = ['no surfacing','flippers']  #標簽分的兩種類別

return dataSet,labels

#划分數據集 dataSet是數據集,axis是划分特征(輸入的是列數),value是列上對應的特征值

def splitDataSet(dataSet,axis,value):  #函數間是引用類型傳遞,會影響原來的變量

retDataSet = []   #定義一個空列表防止影響原來的輸入列表中的數據

for featVec in dataSet:

if featVec[axis] == value:   #三步變換是為了把所有符合條件的行都選出來,把特征值去除,加到列表中,返回

reducedFeatVec = featVec[:axis]   

reducedFeatVec.extend(featVec[axis+1:])  #extend()方法和append的區別

retDataSet.append(reducedFeatVec)

return retDataSet  #返回按axis列上的value值划分的數據集

#選擇最好的數據集划分方式

def chooseBestFeatureToSplit(dataSet):  

numFeatures = len(dataSet) - 1 #特征數

baseEntropy = calcShannonEnt(dataSet) #整個數據集的原始香農熵,用於后面比較

bestInfoGain = 0.0 

bestFeature = -1  #用來存儲特征值最好的那一列的列序號

for i in range(numFeatures):  #i的作用控制列號,表示到底幾個特征變量了

#重復工作為了求出唯一的元素序列  采用set方法,最快

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 > bestFeature):

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=opetator.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(dataSet): #如果所有的類標簽都一樣,遞歸結束

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  #返回決策樹

 

if __name__ == '__main__':

myDat,labels = createDataSet()

# myDat[0][-1] = 'maybe'  #熵越高,混合的數據越多

# print(myDat)

# t=splitDataSet(myDat,1,1)   #划分數據集

# x=calcShannonEnt(myDat)  #求得的香農熵

# print("香農熵是:",x)

# print(t)

# bestFeature=chooseBestFeatureToSplit(myDat)

# print(bestFeature)  

myTree = createTree(myDat,labels)

print(myTree)  #打印ID3的分類決策樹,字典形式

 

#結果分析(決策樹如下):no surfacing ->0->'no'

                                     ->1->flippers->0->'no'

                                                   ->1->'yes'


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM