分类决策树:
由节点和有向边组成。结点有两种类型:内部结点和叶子结点。内部结点表示一个特征或者属性,叶结点表示一个类(也就是最终决定结果)
构建决策树:
- 1 特征选择
- 特征选择的标准是信息增益(在划分数据集之后信息发生的变化)
- 如何计算信息增益?:香农熵(集合信息的度量方式),表示的是随机变量不确定性的度量。如果待分类的事物可能划分在多个分类中,则符号xi的信息定义为:其中p是选择该类的概率
- 计算所有类别所有可能包含的信息期望值公式:其中n是分类数目。熵越大随机变量的不确定性越大。
- 当熵中的概率由数据估计(特别是最大似然估计)得到时,所对应的熵叫,经验熵。
- 编写代码计算经验熵:
"""
数据集标注:
年龄:0代表青年,1代表中年,2代表老年;
有工作:0代表否,1代表是;
有自己的房子:0代表否,1代表是;
信贷情况:0代表一般,1代表好,2代表非常好;
类别(是否给贷款):no代表否,yes代表是。
"""
from math import log
def createDataSet():
dataSet = [[0, 0, 0, 0, 'no'], # 数据集
[0, 0, 0, 1, 'no'],
[0, 1, 0, 1, 'yes'],
[0, 1, 1, 0, 'yes'],
[0, 0, 0, 0, 'no'],
[1, 0, 0, 0, 'no'],
[1, 0, 0, 1, 'no'],
[1, 1, 1, 1, 'yes'],
[1, 0, 1, 2, 'yes'],
[1, 0, 1, 2, 'yes'],
[2, 0, 1, 2, 'yes'],
[2, 0, 1, 1, 'yes'],
[2, 1, 0, 1, 'yes'],
[2, 1, 0, 2, 'yes'],
[2, 0, 0, 0, 'no']]
labels = ['不放贷', '放贷'] # 分类属性
return dataSet, labels # 返回数据集和分类属性
"""
函数说明:计算给定数据集的经验熵
parameters:
dataSet 数据集
Return:
shannonEnt-经验熵
"""
def calcShannonEnt(dataSet):
numEntires=len(dataSet) #返回数据集行数
labelCounts={
}#保存每个标签出现次数的字典
for featVec in dataSet:#对每组特征向量进行统计
currentLabel=featVec[-1]#提取标签信息
if currentLabel not in labelCounts.keys():#如果标签没有放入统计字典,就加入
labelCounts[currentLabel]=0
labelCounts[currentLabel]+=1 #label计数
shannonEnt=0.0 #经验熵
for key in labelCounts: #计算香农熵
prob=float(labelCounts[key])/numEntires #选择该标签的概率
shannonEnt -=prob*log(prob,2) #利用公式计算
return shannonEnt
if __name__=='__main__':
dataSet,features=createDataSet()
print(dataSet)
print(calcShannonEnt(dataSet))
- 信息增益:我们要选信息增益最大,即选择对最终分类结果影响最大的特征作为分类特征。
- 条件熵:H(Y|X)表示在已知随机变量x的条件下随机变量Y的不确定性;随机变量x给定的条件下随机变量y的条件熵H(Y|X)定义为:x给定条件下y的条件概率分布的熵对x的数学期望:
- 当条件熵中的概率由数据估计(特别是极大似然估计)得到时,所对应的条件熵为条件经验熵。
- 特征A对训练数据集D的信息增益g(D,A),定义为集合D的经验熵H(D)与特征A给定条件下D的经验条件熵H(D|A)之差:
- 一般的,熵H(D)与条件熵H(D|A之差成为互信息。决策树学习中的信息增益等价于训练数据集中类与特征的互信息。
- 编写代码计算信息增益
"""
数据集标注:
年龄:0代表青年,1代表中年,2代表老年;
有工作:0代表否,1代表是;
有自己的房子:0代表否,1代表是;
信贷情况:0代表一般,1代表好,2代表非常好;
类别(是否给贷款):no代表否,yes代表是。
"""
from math import log
def createDataSet():
dataSet = [[0, 0, 0, 0, 'no'], # 数据集
[0, 0, 0, 1, 'no'],
[0, 1, 0, 1, 'yes'],
[0, 1, 1, 0, 'yes'],
[0, 0, 0, 0, 'no'],
[1, 0, 0, 0, 'no'],
[1, 0, 0, 1, 'no'],
[1, 1, 1, 1, 'yes'],
[1, 0, 1, 2, 'yes'],
[1, 0, 1, 2, 'yes'],
[2, 0, 1, 2, 'yes'],
[2, 0, 1, 1, 'yes'],
[2, 1, 0, 1, 'yes'],
[2, 1, 0, 2, 'yes'],
[2, 0, 0, 0, 'no']]
labels = ['不放贷', '放贷'] # 分类属性
return dataSet, labels # 返回数据集和分类属性
"""
函数说明:计算给定数据集的经验熵
parameters:
dataSet 数据集
Return:
shannonEnt-经验熵
"""
def calcShannonEnt(dataSet):
numEntires=len(dataSet) #返回数据集行数
labelCounts={
}#保存每个标签出现次数的字典
for featVec in dataSet:#对每组特征向量进行统计
currentLabel=featVec[-1]#提取标签信息
if currentLabel not in labelCounts.keys():#如果标签没有放入统计字典,就加入
labelCounts[currentLabel]=0
labelCounts[currentLabel]+=1 #label计数
shannonEnt=0.0 #经验熵
for key in labelCounts: #计算香农熵
prob=float(labelCounts[key])/numEntires #选择该标签的概率
shannonEnt -=prob*log(prob,2) #利用公式计算
return shannonEnt
"""
函数说明:按照给定特征划分数据集
parameter:
dataSet -待划分的数据集
axis-划分数据集的特征
value-需要返回的特征的值
"""
def splitDataSet(dataSet,axis,valus):
retDataSet=[] #创建返回的数据集列表
for featVec in dataSet: #遍历数据集
if featVec[axis]==dataSet:
reducedFeatVec=featVec[:axis] #去掉axis特征
reducedFeatVec.extend(featVec[axis+1:]) #将符合条件的添加到返回的数据集
retDataSet.append(reducedFeatVec)
return retDataSet #返回划分后的数据集
"""
函数说明:选择最优特征
Parameters:
dataSet
returns:
bestFeature -信息增益最大的(最优)特征的索引值
"""
def chooseBestFeatureToSplit(dataSet):
numFeatures=len(dataSet[0])-1 #特征数量
baseEntropy=calcShannonEnt(dataSet) #计算数据集的香农熵
bestInfoGain=0.0 #信息增益
bestFeature=-1 #最优特征的索引值
for i in range(numFeatures): #遍历所有特征
#获取dataSet的第i个所有特征值
featList=[example[i] for example in