1. 程式人生 > >機器學習_決策樹Python代碼詳解

機器學習_決策樹Python代碼詳解

機器 one math n) sco atl return 復雜度 重復

決策樹優點:計算復雜度不高,輸出結果易於理解,對中間值的缺失不敏感,可以處理不相關特征數據;

決策樹缺點:可能會產生過度匹配問題。

決策樹的一般步驟:

(1)代碼中def 1,計算給定數據集的香農熵:

技術分享圖片

其中n為類別數,D為數據集,每行為一個樣本,pk 表示當前樣本集合D中第k類樣本所占的比例,Ent(D)越小,D的純度越高,即表示D中樣本大部分屬於同一類;反之,D的純度越低,即數據集D中的類別數比較多。

(2)代碼中def 2,選擇最好的數據集劃分方式,即選擇信息增益最大的屬性:

技術分享圖片

其中

技術分享圖片

這裏V表示屬性a的可能的取值數,Dv表示屬性a上取值為av的樣本。

(3)代碼中 def 3,按照給定特征劃分數據集:選取最優屬性後,再從屬性的各個取值中選取最優的屬性,以此類推。

(4)代碼中def 5,遞歸構造數,數的結束標誌為:a、類別完全相同則停止劃分;b、代碼中def 4,如果數據集已經處理了所有屬性,但是類標簽依然不是唯一的,此時采用多數表決法,即遍歷完所有特征時返回出現次數最多的類別。

from math import log

# 計算數據集的信息熵,熵越小,說明數據集的純度越高
def calcShannonEnt(dataset): # def 1
numEntries = len(dataset) # 樣本數,這裏的dataSet是列表
labelCounts = {} #定義一個字典,key為類別,值為類別數
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 * log(prob,2)
return shannonEnt # 信息熵

# 選出最好的數據集劃分方式,即找出具有最大信息增益的特征
def chooseBestFeatureToSplit(dataSet): #def 2
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] #第i列特征的所有特征的取值
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 # 表示屬性為value的信息增益
if (infoGain > bestInfoGain):
bestInfoGain = infoGain
bestFeature = i
return bestFeature # 具有最大信息增益的特征


# 按照給定特征維數劃分數據集,數據集中一行為一個樣本
# def 3
def splitDataSet(dataSet,axis,value): # axis可表示數據集的列,也就是特征為數,value表示特征的取值
retDataSet = []
for featVec in dataSet:
if featVec[axis] == value:
reducedFeatVec = featVec[:axis] # 在數據集中去掉axis這一列
reducedFeatVec.extend(featVec[axis+1:])
retDataSet.append(reducedFeatVec)
return retDataSet # 表示去掉在axis中特征值為value的樣本後而得到的數據集


# 當處理了所有屬性,但是類標簽依然不是唯一的,此時采用多數表決法決定該葉子節點的分類
def majorityCnt(classList): # def 4
classCount = {}
for vote in classList:
if vote not in classCount.keys():
classCount[vote] = 0
classCount += 1
sortedClassCount = sorted(classCount.items(),key=lambda classCount: classCount[1],reverse = True)
return sortedClassCount[0][0]

# 創建樹
def createTree(dataSet,labels): # def 5
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

def createDateSet():
dataSet = [[1,1,‘yes‘],[1,1,‘yes‘],[1,0,‘no‘],[0,1,‘no‘],[0,1,‘no‘]]
labels = [‘no surfacing‘,‘flippers‘] #屬性名
return dataSet,labels


myData,myLabel = createDateSet()
createTree(myData,myLabel)
print(createTree(myData,myLabel))
#print(chooseBestFeatureToSplit(myData))
# print(splitDataSet(myData,0,1))
# print(splitDataSet(myData,0,0))

機器學習_決策樹Python代碼詳解