主要记录决策树的构造,绘制决策树还未理解透彻。
构造决策树主要需要完成一下部分:
1. 计算不同分类的香农熵
2. 根据香农熵划分数据集
3. 通过递归构建出决策树
香农熵的计算
在记录香农熵之前首先要说明的定义:
l ( x i ) = − l o g 2 p ( x i ) l(x_{i}) = -log_{2}p(x_{i}) l(xi)=−log2p(xi)
其中 p ( x i ) p(x_{i}) p(xi) 指的是这个时间按发生的概率。
为了计算熵,我们需要计算所有可能值包含的信息期望值,通过下面公式获得:
H
=
−
∑
i
=
1
n
p
(
x
i
)
l
o
g
2
p
(
x
i
)
H=-\sum_{i=1}^{n} p (x_{i})log_{2}p(x_{i})
H=−i=1∑np(xi)log2p(xi)
计算香农熵的代码:
def calcShannoEnt(dataset):
numEntries = len(dataset)
labelCounts = {}
for featVec in dataset:
currentLabel = featVec[-1]
if currentLabel not in labelCounts.keys():
labelCounts[currentLabel] = 0
labelCounts[currentLabel] += 1
shannoEnt = 0.0
# 计算香农熵
for key in labelCounts:
prob = float(labelCounts[key]) / numEntries
shannoEnt -= prob*log(prob, 2)
return shannoEnt
数据集的划分
类似于物理的熵,当其值越小时,其混乱程度越低,那么在分类上再说也就是分类越明显,因此将通过计算香农熵相对原始值减少多少来寻找数据集中最优的划分条件。
代码如下:
def chooseBestFeatureToSplit(dataset):
# 由于最后一项用于记录他的label所以的特征数量要减一
numFeature = len(dataset[0]) - 1
baseEntropy = calcShannoEnt(dataset)
bestInfoGain = 0.0
bestFeature = -1
for i in range(numFeature):
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 * calcShannoEnt(subDataSet)
infoGain = baseEntropy - newEntropy
if (infoGain > bestInfoGain):
bestInfoGain = infoGain
bestFeature = i
return bestFeature
其中一使用到一个将数据集提取的函数 splitDataSet()
代码如下:
def splitDataSet(dataSet, axis, value):
retDataSet = []
for featVec in dataSet:
# 如果对应特征的值与value相同那么将他提取出来
if featVec[axis] == value:
reducedFeatVec = featVec[:axis]
reducedFeatVec.extend(featVec[axis+1:])
retDataSet.append(reducedFeatVec)
return retDataSet
使用递归生成决策树
由于我们要使用所有的特征来分类,所以我们的基线条件应该时特征的数量为0,不过特征数量为零但是统一数据集下对于不同的对象,他们的label可能不同,这是我们取数量占比大的label作为该节点的分类。
选取多数的函数如下:
def majorityent(classlist):
classCount = {}
for vote in classlist:
if vote not in classCount.keys():
classCount[vote] = 0
classCount[vote] += 1
sortedClassCount = sorted(list(classCount.iteritems()), key=operator.itemgetter(1), reverse=True)
return sortedClassCount[0][0]
下面就可已使用i递归创建决策树了,
def createTree(dataSet, labels):
# 获取分类情况
classList = [example[-1] for example in dataSet]
# 基线情况
if len(classList) == classList.count(classList[0]):
return classList[0]
if len(dataSet[0]) == 1:
return repeat0(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
对于决策树的绘制还不是很懂,再研究研究在继续~~~