機器學習 python實例完成―決策樹
來源:程序員人生 發布時間:2015-03-30 08:05:12 閱讀次數:3848次
決策樹學習是利用最廣泛的歸納推理算法之1,是1種逼近離散值目標函數的方法,在這類方法中學習到的函數被表示為1棵決策樹。決策樹可使用不熟習的數據集合,并從中提取出1系列規則,機器學習算法終究將使用這些從數據集中創造的規則。決策樹的優點為:計算復雜度不高,輸出結果易于理解,對中間值的缺失不敏感,可以處理不相干特點數據。缺點為:可能產生過度匹配的問題。決策樹適于處理離散型和連續型的數據。
在決策樹中最重要的就是如何選取用于劃分的特點
在算法中1般選用ID3,D3算法的核心問題是選取在樹的每一個節點要測試的特點或屬性,希望選擇的是最有助于分類實例的屬性。如何定量地衡量1個屬性的價值呢?這里需要引入熵和信息增益的概念。熵是信息論中廣泛使用的1個度量標準,刻畫了任意樣本集的純度。
假定有10個訓練樣本,其中6個的分類標簽為yes,4個的分類標簽為no,那熵是多少呢?在該例子中,分類的數目為2(yes,no),yes的幾率為0.6,no的幾率為0.4,則熵為 :

其中value(A)是屬性A所有可能值的集合,
是S中屬性A的值為v的子集
,即。上述公式的第1項為原集合S的熵,第2項是用A分類S后熵的期望值,該項描寫的期望熵就是每一個子集的熵的加權和,權值為屬于的樣本占原始樣本S的比例
。所以Gain(S,
A)是由于知道屬性A的值而致使的期望熵減少。
完全的代碼:
# -*- coding: cp936 -*-
from numpy import *
import operator
from math import log
import operator
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
def calcShannonEnt(dataSet):
numEntries = len(dataSet)
labelCounts = {} # a dictionary for feature
for featVec in dataSet:
currentLabel = featVec[⑴]
if currentLabel not in labelCounts.keys():
labelCounts[currentLabel] = 0
labelCounts[currentLabel] += 1
shannonEnt = 0.0
for key in labelCounts:
#print(key)
#print(labelCounts[key])
prob = float(labelCounts[key])/numEntries
#print(prob)
shannonEnt -= prob * log(prob,2)
return shannonEnt
#依照給定的特點劃分數據集
#根據axis等于value的特點將數據提出
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
#選取特點,劃分數據集,計算得出最好的劃分數據集的特點
def chooseBestFeatureToSplit(dataSet):
numFeatures = len(dataSet[0]) - 1 #剩下的是特點的個數
baseEntropy = calcShannonEnt(dataSet)#計算數據集的熵,放到baseEntropy中
bestInfoGain = 0.0;bestFeature = ⑴ #初始化熵增益
for i in range(numFeatures):
featList = [example[i] for example in dataSet] #featList存儲對應特點所有可能得取值
uniqueVals = set(featList)
newEntropy = 0.0
for value in uniqueVals:#下面是計算每種劃分方式的信息熵,特點i個,每一個特點value個值
subDataSet = splitDataSet(dataSet, i ,value)
prob = len(subDataSet)/float(len(dataSet)) #特點樣本在總樣本中的權重
newEntropy = prob * calcShannonEnt(subDataSet)
infoGain = baseEntropy - newEntropy #計算i個特點的信息熵
#print(i)
#print(infoGain)
if(infoGain > bestInfoGain):
bestInfoGain = infoGain
bestFeature = i
return bestFeature
#如上面是決策樹所有的功能模塊
#得到原始數據集以后基于最好的屬性值進行劃分,每次劃分以后傳遞到樹分支的下1個節點
#遞歸結束的條件是程序遍歷完成所有的數據集屬性,或是每個分支下的所有實例都具有相同的分類
#如果所有實例具有相同的分類,則得到1個葉子節點或終止快
#如果所有屬性都已被處理,但是類標簽仍然不是肯定的,那末采取多數投票的方式
#返回出現次數最多的分類名稱
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[⑴] for example in dataSet]#將最后1行的數據放到classList中,所有的種別的值
if classList.count(classList[0]) == len(classList): #種別完全相同不需要再劃分
return classList[0]
if len(dataSet[0]) == 1:#這里為何是1呢?就是說特點數為1的時候
return majorityCnt(classList)#就返回這個特點就好了,由于就這1個特點
bestFeat = chooseBestFeatureToSplit(dataSet)
print('the bestFeatue in creating is :')
print(bestFeat)
bestFeatLabel = labels[bestFeat]#運行結果'no surfacing'
myTree = {bestFeatLabel:{}}#嵌套字典,目前value是1個空字典
del(labels[bestFeat])
featValues = [example[bestFeat] for example in dataSet]#第0個特點對應的取值
uniqueVals = set(featValues)
for value in uniqueVals: #根據當前特點值的取值進行下1級的劃分
subLabels = labels[:]
myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet,bestFeat,value),subLabels)
return myTree
#對上面簡單的數據進行小測試
def testTree1():
myDat,labels=createDataSet()
val = calcShannonEnt(myDat)
print 'The classify accuracy is: %.2f%%' % val
retDataSet1 = splitDataSet(myDat,0,1)
print (myDat)
print(retDataSet1)
retDataSet0 = splitDataSet(myDat,0,0)
print (myDat)
print(retDataSet0)
bestfeature = chooseBestFeatureToSplit(myDat)
print('the bestFeatue is :')
print(bestfeature)
tree = createTree(myDat,labels)
print(tree)
對應的結果是:
>>> import TREE
>>> TREE.testTree1()
The classify accuracy is: 0.97%
[[1, 1, 'yes'], [1, 1, 'yes'], [1, 0, 'no'], [0, 1, 'no'], [0, 1, 'no']]
[[1, 'yes'], [1, 'yes'], [0, 'no']]
[[1, 1, 'yes'], [1, 1, 'yes'], [1, 0, 'no'], [0, 1, 'no'], [0, 1, 'no']]
[[1, 'no'], [1, 'no']]
the bestFeatue is :
0
the bestFeatue in creating is :
0
the bestFeatue in creating is :
0
{'no surfacing': {0: 'no', 1: {'flippers': {0: 'no', 1: 'yes'}}}}
最好再增加使用決策樹的分類函數
同時由于構建決策樹是非常耗時間的,由于最好是將構建好的樹通過 python 的 pickle 序列化對象,將對象保存在
磁盤上,等到需要用的時候再讀出
def classify(inputTree,featLabels,testVec):
firstStr = inputTree.keys()[0]
secondDict = inputTree[firstStr]
featIndex = featLabels.index(firstStr)
key = testVec[featIndex]
valueOfFeat = secondDict[key]
if isinstance(valueOfFeat, dict):
classLabel = classify(valueOfFeat, featLabels, testVec)
else: classLabel = valueOfFeat
return classLabel
def storeTree(inputTree,filename):
import pickle
fw = open(filename,'w')
pickle.dump(inputTree,fw)
fw.close()
def grabTree(filename):
import pickle
fr = open(filename)
return pickle.load(fr)
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈