版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/mansir123/article/details/79398136
决策树中算法采用的ID3.划分数据集基于 特征。其中采用分类依据为信息论中的信息增益和信息熵(香农熵)。
机器学习中香农熵计算公式为:
其中xi表示分类,p(xi)表示xi分类的概率。
首先,创建数据集及计算香农熵
from math import log
def calcShannonEnt(dataset): #香农熵计算函数
numEnts=len(dataset)
labelCounts={} #记录标签及对应的个数
for featVec in dataset:
currentLabel=featVec[-1] #取出数组中最后一项‘n’或者‘y’的作为标签
if currentLabel not in labelCounts.keys(): #如果当前标签在labelCounts中无记录,则添加
labelCounts[currentLabel]=0
labelCounts[currentLabel]+=1 #标签对应数量计数
shannonEnt=0.0
print(labelCounts)#输出标签及对应个数
for key in labelCounts:
prob=float(labelCounts[key])/numEnts #同标签出现的概率,即p(xi)
shannonEnt-=prob*log(prob,2) #计算香农熵 -p(xi)*log2(p(xi))的加和
return shannonEnt
def createDataset(): #数据集创建函数
dataset=[
[1,1,'y'],
[1,1,'y'],
[1,0,'n'],
[0,1,'n'],
[0,1,'n']
]
labels=["no serfacing","flippers"]
return dataset,labels
myData,labels=createDataset()
myData[0][-1]='maybe'#修改数据集中第一个的标签为 maybe
print(myData)
print(calcShannonEnt(myData))
输出结果为
[[1, 1, 'maybe'], [1, 1, 'y'], [1, 0, 'n'], [0, 1, 'n'], [0, 1, 'n']]
{'maybe': 1, 'y': 1, 'n': 3}
1.3709505944546687
得到熵,下一步按照最大信息增益的方法划分数据集。
原理是取各属性进行熵的计算。取最高信息增益的属性为最佳属性。
def chooseBestFeatureToSplit(dataset):
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] #遍历获取该列所有值
print("featList:",featList)
uniqueVals=set(featList) #从列表中创建集合,得到不重复的所有可能取值
print("uniquevals",uniqueVals)
newEntropy=0.0
for value in uniqueVals:
subDataset=splitDataSet(dataset,i,value)
print("subDataset:",subDataset)
prob=len(subDataset)/float(len(dataset))
newEntropy+=prob*calcShannonEnt(subDataset)
print("%d 列属性的熵为:"%i,newEntropy)
infoGain=baseEntropy-newEntropy #计算每一个属性值对应的熵值并求和。结果与原始熵值的差即为信息增益。增益越大说明所占决策权越大
print("inforgain:",infoGain)
if(infoGain>bestInfoGain):
bestInfoGain=infoGain
bestFeature=i
return bestFeature
print("bestFeature:",chooseBestFeatureToSplit(myData))
输出结果为:
featList: [1, 1, 1, 0, 0]
uniquevals {0, 1}
subDataset: [[1, 'n'], [1, 'n']]
{'n': 2}
subDataset: [[1, 'y'], [1, 'y'], [0, 'n']]
{'y': 2, 'n': 1}
0 列属性的熵为: 0.5509775004326937
inforgain: 0.4199730940219749
featList: [1, 1, 0, 1, 1]
uniquevals {0, 1}
subDataset: [[1, 'n']]
{'n': 1}
subDataset: [[1, 'y'], [1, 'y'], [0, 'n'], [0, 'n']]
{'y': 2, 'n': 2}
1 列属性的熵为: 0.8
inforgain: 0.17095059445466854
bestFeature: 0
下面构建决策树
代码如下:
def majorityCnt(classList): #返回出现次数最多的分类名称
classCount={}
for vote in classList:
if vote not in classCount.keys():classCount[vote]=0 #创建分类(即字典)并计数
classCount[vote]+=1
sortedClassCount=sorted(classCount.items(),key=operator.itemgetter(1),reverse=True) #排序,True升序
return sortedClassCount[0][0]
def createTree(dataSet,labels):
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
print("createtree:",createTree(myData,labels))
最终输出结果:
createtree: {'no serfacing': {0: 'n', 1: {'flippers': {0: 'n', 1: 'y'}}}}
结果为多层嵌套的叶节点