1.预备知识
1.信息增益
在信息论与概率统计中,熵(entropy)是表示随机变量的不确定性的度量,熵值越大表明越不确定,设X是随机变量,则熵定义如下
计算信息增益如下:
2代码解析
#coding:gbk
'''
Created on 2014年11月4日
@author: dell
'''
from numpy import log2
import operator
'''
总的信息增益是依据分类来算的,即line[-1],统计出每个占多少总数
len(y1)/total_num然后再用D1/D(p*log(P)) D1表示占分类中标签占多少个
@function 计算熵
'''
def calcShannonEnt(dataSet):
labels={}
total_num = len(dataSet)
for line in dataSet:
key=line[-1]
if key not in labels.keys():
labels[key]=1
else:
labels[key]+=1
shannon=0.0
for key in labels.keys():
p = float(labels[key])/total_num
shannon-= p *log2(p)
return shannon
'''
@function 创建一个数据矩阵
'''
def creatDataSet():
dataset = [[1,1,'yes'],[1,1,'yes'],[1,0,'no'],[0,1,'no'],[0,1,'no']]
labels = ['no surfacing','flippers']
return dataset,labels
'''
@function 划分数据集,将数据集在axis列中是value的值删除
@param dataSet是要划分的数据集,axis是要特征的具体位置,vlaue是具体的值,
'''
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
'''
@function 选择最好的特征划分数据集
@param dataSet是要划分的数据集
@return 返回的最优特征的下标
'''
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] #特征值列表
uniqueVals = set(featList) #特征列表去重,
newEntropy = 0.0
for value in uniqueVals:
subdataSet = splitDataSet(dataSet, i, value) #去除特征值的数据集
prob = len(subdataSet)/float(len(dataSet)) #这个就是Di在D中的比例
newEntropy += prob*calcShannonEnt(subdataSet) #先算出来某一个特征在总特征集的比例,然后再将这个特征值删除,计算删除特征值后的数据集的熵
infoGain = baseEntropy -newEntropy #信息增益是拿总分类的熵-特征的熵,信息增益最大即为最优特征
if infoGain > bestInfoGain:
bestInfoGain = infoGain
bestFeature = i
return bestFeature
'''
@function 包含类标签的列表
#对具有相同特征值的类别排序,采用投票的方法。也就是类别多的 即为输出类别
'''
def majorityCnt(classList):
classCount={} #用字典存储一个类别列表,然后用sorted函数输出一个数目最多的,sortedClassCount好像是一个元组
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) #sorted是排序函数,按照key值排序从大到小, b=operator.itemgetter(1) //定义函数b,获取对象的第1个域的值
return sortedClassCount[0][0] #返回频率最高的分类
'''
@param dataSet:数据集,labels:类标签
@function 创建决策树,先选定最佳特征值,然后子树就是在删除最佳特征的子数据集上递归进行构建决策树
'''
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:{}} #已经构建了好了一个关于myTree的字典,只需递归构建即可,key是设置的是最优路径的分类标签值,value是下一个
del(labels[bestFeat]) #删除这个最佳特征,方便为下一步递归的建立决策树
featValues = [example[bestFeat] for example in dataSet] #得到列表包含的所有属性值
uniqueVals = set(featValues)
for value in uniqueVals:
subLabels = labels[:] #copy all of labels, so trees don't mess up existing labels,因为bestLabel已经被删除了
myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value),subLabels) #递归的建立决策树
return myTree