一、决策树的概述
1.1 决策树的概念
1.2 决策树分类举例
1.3 决策树的步骤
1.4 决策树的优缺点
二、决策树的三种实现算法
2.1ID3算法
# 计算给定数据集的熵
def calcShannonEnt(dataSet):
numEntries = len(dataSet) #获得数据集的行数
labelCounts = {} #用于保存每个标签出现次数的字典
for featVec in dataSet:
currentLabel = featVec[-1] #提取标签信息
if currentLabel not in labelCounts.keys(): #如果标签未放入统计次数的字典,则添加进去
labelCounts[currentLabel] = 0
labelCounts[currentLabel] += 1 #标签计数
shannonEnt = 0.0 #熵初始化
for key in labelCounts:
prob = float(labelCounts[key])/numEntries #选择该标签的概率
shannonEnt -= prob*log(prob, 2) #以2为底求对数
return shannonEnt #返回经验熵
# 按照给定特征划分数据集
def splitDataSet(dataSet,axis,value): #dataSet:带划分数据集 axis:划分数据集的特征 value:需要返回的特征的值
retDataSet=[] #创建新的list对象
for featVec in dataSet: #遍历元素
if featVec[axis] == value: #符合条件的,抽取出来
reducedFeatVec = featVec[:axis]
reducedFeatVec.extend(featVec[axis+1:])
retDataSet.append(reducedFeatVec)
return retDataSet
# 选择最好的数据集划分方式 ID3算法——信息增益
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] #获取dataSet的第i个所有特征
uniqueVals = set(featList) #创建set集合{},元素不可重复
newEntropy = 0.0 #信息熵
for value in uniqueVals: #循环特征的值
subDataSet = splitDataSet(dataSet, i, value) #subDataSet划分后的子集
prob = len(subDataSet) / float(len(dataSet)) #计算子集的概率
newEntropy += prob * calcShannonEnt((subDataSet))
infoGain = baseEntropy - newEntropy #计算信息增益
print("第%d个特征的信息增益为%.3f" % (i, infoGain)) #打印每个特征的信息增益
if (infoGain > bestInfoGain): #计算信息增益
bestInfoGain = infoGain #更新信息增益,找到最大的信息增益
bestFeature = i #记录信息增益最大的特征的索引值
return bestFeature #返回信息增益最大特征的索引值
# 统计出现次数最多的元素(类标签)
def majorityCnt(classList):
classCount={} #统计classList中每个类标签出现的次数
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[-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
结果测试:
#ID3算法 生成的决策树
{'有自己的房子': {0: {'有工作': {0: 'no', 1: {'年龄': {0: {'信贷情况': {'no': 'no', 'yes': 'yes'}}, 2: 'yes'}}}}, 1: {'年龄': {0: {'信贷情况': {'no': 'no', 'yes': 'yes'}}, 1: 'yes', 2: 'yes'}}}}

2.2C4.5算法
#选择最好的数据集划分方式 C4.5算法——信息增益率
def chooseBestFeatureToSplit(dataSet):
numFeatures = len(dataSet[0]) - 1 #特征数量
baseEntropy = calcShannonEnt(dataSet) #获取信息熵
bestinfoGainratio = 0.0 #信息增益率初始化为0,
bestFeature = -1 #最优的划分特征,初始化为-1
for i in range(numFeatures): #遍历所有的特征
featList = [example[i] for example in dataSet] #创建list用来存每个样本在第i维度的特征值
uniqueVals = set(featList) #获取该特征下的所有不同的值
newEntropy = 0.0 #初始化信息熵
IV = 0.0
for value in uniqueVals: #遍历该特征维度下对应的所有特征值
subDataSet = splitDataSet(dataSet, i, value) #划分数据集
prob = len(subDataSet)/float(len(dataSet))
newEntropy += prob * calcShannonEnt(subDataSet)
IV -= prob * log(prob,2) #计算信息增益率
infoGain = baseEntropy - newEntropy #计算信息增益
if IV == 0.0:
infoGainratio = 0.0
else:
infoGainratio = float(infoGain) / float(IV)
if (infoGainratio > bestinfoGainratio):
bestinfoGainratio = infoGainratio #找到最大的信息增益率
bestFeature = i #记录信息增益率最大的索引值
return bestFeature
结果测试:
#C4.5算法 生成的决策树
{'有自己的房子': {0: {'有工作': {0: 'no', 1: {'年龄': {0: {'信贷情况': {'yes': 'yes', 'no': 'no'}}, 2: 'yes'}}}}, 1: {'有工作': {0: 'yes', 1: {'年龄': {0: {'信贷情况': {'yes': 'yes', 'no': 'no'}}, 1: 'yes'}}}}}}

2.3CART算法
# 计算概率
def calcProbabilityEnt(dataSet):
numEntries = len(dataSet) # 数据集大小
feaCounts = 0 # 特征数量
feature = dataSet[0][len(dataSet[0]) - 1]
for feaVec in dataSet:
if feaVec[-1] == feature:
feaCounts += 1
probabilityEnt = float(feaCounts) / numEntries #概率= 特征数量/数据集大小
return probabilityEnt
# 选择最好的数据集划分方式 CAR算法——基尼指数
def chooseBestFeatureToSplit(dataSet):
numFeatures = len(dataSet[0]) - 1 #特征数量
if numFeatures == 1:
return 0
bestGini = 1 #最佳基尼指数
bestFeature = -1 #最优的划分特征,初始化为-1
for i in range(numFeatures): # 遍历所有的特征
featList = [example[i] for example in dataSet]
feaGini = 0 # 定义特征的值的基尼系数
uniqueVals = set(featList) #获取该特征下的所有不同的值
for value in uniqueVals:
subDataSet = splitDataSet(dataSet, i, value) #划分数据集
prob = len(subDataSet) / float(len(dataSet))
probabilityEnt = calcProbabilityEnt(subDataSet)
feaGini += prob * (2 * probabilityEnt * (1 - probabilityEnt))
if (feaGini < bestGini):
bestGini = feaGini #基尼指数
bestFeature = i #记录基尼指数最小的索引值
return bestFeature
代码测试:
#CAR算法 生成的决策树
{'有自己的房子': {0: {'有工作': {0: 'no', 1: {'年龄': {0: {'信贷情况': {1: 'yes'}}, 2: 'yes'}}}}, 1: {'年龄': {0: {'有工作': {1: {'信贷情况': {0: 'yes'}}}}, 1: 'yes', 2: 'yes'}}}}

三、三种不同实现算法的比较
ID3算法:
ID3算法核心就是“最大信息熵增益” 原则选择划分当前数据集的最好特征。
而且对于连续型特征,比如长度,密度都是连续值,无法在ID3运用,因为一开始我用的鸢尾花实例数据,ID3不能判断连续型量。
前面也说到了,利用信息熵划分属性,会对倾向于可取值数目较多的属性。
没有考虑过拟合的问题。
C4.5算法:
C4.5算法流程与ID3算法相类似,只不过将信息增益改为信息增益率,以解决偏向取值较多的属性的问题。
可以处理属性变量为连续型的,将连续的特征离散化。
CAR算法:
CART算法使用基尼系数来代替信息增益比,基尼系数代表了模型的不纯度,基尼系数越小,则不纯度越低,特征越好。这和信息增益及信息增益率是相反的。
四、实验总结
决策树的实验本质就是做分类任务,在本次实验中我学会了ID3、C4.5、CART三种算法。一开始会对这些算法中提到的新概念感到陌生害怕,经过不懈的努力在老师同学和网络的帮助下我逐渐对这些新概念有了了解得到了消化,总的来说本次实验获益匪浅。

1070

被折叠的 条评论
为什么被折叠?



