前言

所谓构建决策树,

就是递归的对数据集参数进行“最优特征”的选择。然后按最优特征分类成各个子数据集,继续递归。

最优特征的选择:依次计算按照各个特征进行分类以后数据集的熵,各个子数据集的熵比较后,其中拥有最小的熵的数据集就是最优的分类结果,此次分类的特征就是最优特征。

熵的计算:熵计算的是数据集的纯净程度,数据集的熵的大小只和数据集中各数据样本的最终分类结果的分布有关。假设数据集中所有数据都是“同一种类”的数据,那么其熵就是0,表示是最纯净的数据。

(所以最优特征的选择就变成了,先计算分类前的数据集的熵,再计算按某种特征分类后其各个子数据集的熵的期望,然后取原数据集熵与分类后的熵期望之差作为评价分类效果的标准。)

(此处之所以计算分类后所有子数据集的熵的期望其实很好理解。期望也可以看成一堆离散数据的平均值,假设我们把原数据集分成了三堆子数据集,这三堆子数据集哪一堆也不能代表分类后的结果,只有三堆总结果再求个期望也就是三堆的平均值,才能代表分类后的结果)

熵的计算

我们用数据集中各结果分类出现的概率来作为计算熵的决定因素。

假设整个样本数据集中样本都有着“统一的分类结果”时,出现该分类结果的概率是100%,其熵就是0。

而如果数据集中有10个样本,每个样本都有一个独立的结果分类,那么出现每一种结果的概率都是10%,这种结果的不确定性自然要比上一个大(上一个可是100%的确定结果),其最终熵值肯定也要更大。

至此我们可以看出,我们需要找到一个函数能把事件出现的概率映射成熵值。

这个函数就是以下这个函数

其函数图像为

x轴是事件出现的概率

y轴是熵的值

通过图像我们可以看出随着事件出现的概率越来越大,熵也越来越小,直至到0。

假设数据集中一共有出现三种分类结果的可能,该数据集的熵自然是算出这三种分类结果的熵后在求其三者的期望,使用期望作为该数据集的熵。

python代码实现如下:

from math import log

"""
数据集,
二维数组中的前三个元素都是特征,
最后一个元素是样本的分类结果。
"""
data = [["有眼镜", "短发", "胖", "男"],
["有眼镜", "长发", "瘦", "女"],
["有眼镜", "短发", "胖", "女"],
["没眼镜", "长发", "胖", "男"],
["没眼镜", "短发", "瘦", "男"]] """
data:需要计算熵的数据集
return:该数据集的熵 计算数据集的熵
"""
def calcShannon(data):
# 熵
shannonMean = 0
# 数据总量
sumDataNum = len(data)
# 数据集的所有分类情况
classify = [man[-1] for man in data]
# 循环每一种分类结果,计算该分类结果的熵,并求期望
for resClassify in set(classify):
# 该分类结果的“发生”概率
p = classify.count(resClassify) / sumDataNum
# 计算该分类结果的熵
shannon = -log(p, 2)
# 求期望
shannonMean += p * shannon
return shannonMean print(calcShannon(data))

构建决策树

我们的最终目的是要构建出下图结构的决策树。

上图转换成python字典数据格式为:

{特征1:{值1:yes,值2:{特征2:{值1:no,值2:yes}}}}

完整python代码如下:

from math import log

"""
数据集,
二维数组中的前三个元素都是特征,
最后一个元素是样本的分类结果。
"""
data = [["有眼镜", "短发", "胖", "男"],
["有眼镜", "长发", "瘦", "女"],
["有眼镜", "短发", "胖", "女"],
["没眼镜", "长发", "胖", "男"],
["没眼镜", "短发", "瘦", "男"],
["有眼镜", "长发", "瘦", "女"],
["有眼镜", "长发", "胖", "男"]] """
样本参数中各个特征的描述信息
"""
labels = ["是否戴眼镜", "头发长短", "身材"] """
计算数据集的熵 data:需要计算熵的数据集 return:该数据集的熵
"""
def calcShannon(data):
# 熵
shannonMean = 0
# 数据总量
sumDataNum = len(data)
# 数据集的所有分类情况
classify = [man[-1] for man in data]
# 循环每一种分类结果,计算该分类结果的熵,并求期望
for resClassify in set(classify):
# 该分类结果的“发生”概率
p = classify.count(resClassify) / sumDataNum
# 计算该分类结果的熵
shannon = -log(p, 2)
# 求期望
shannonMean += p * shannon
return shannonMean """
统计分类数组中出现最多的项,并返回该项的值
"""
def statisticsMostClassify(classify):
map = {}
for resClassify in classify:
value = map.get(resClassify)
if value:
map[resClassify] = value + 1
else:
map[resClassify] = 1
mostClassify = sorted(map.items(), key=lambda item: item[1])
return mostClassify[-1][0] """
对数据进行分类,并返回分类后的结果(如按照a特征分类后,分类后的结果数据集中就没有a特征值了) index:按照第几个特征开始分类,从0开始
value:按照该特征的什么值进行分类
data:待分类数据
"""
def categorizationOfData(index, value, data):
resData = []
# 循环每一个样本,如果第index个特征的值符合指定特征,就把该特征删除后保存
for man in data:
if man[index] == value:
tmpMan = man[:]
tmpMan.pop(index)
resData.append(tmpMan)
return resData """
D3算法构建决策树
步骤:
0、获取数据集
1、判断当前数据集是否需要继续分类,如不需要,则返回结果分类
2、找到最优特征
3、根据最优特征进行分类,并把最优特征删去
4、
"""
def createTree(data, labels):
classify = [man[-1] for man in data]
# 如果当前数据集数据都是同一分类结果则不用继续分类
if len(set(classify)) == 1:
return classify[0] # 如果数据集中的样本没有特征了,则返回数据集中出现最多的分类结果
if not labels:
return statisticsMostClassify(classify) # 原数据集香农熵
originalShannon = calcShannon(data)
# 熵差
diffShannon = 0
# 最优特征(index下标)
bestFeatureIndex = 0
# 按照最优特征分类后的结果{分类结果值:分类后的数据集}
bestClassifyData = {}
# 循环计算按照每一个特征分类后的结果,选择其中使得熵差值最大的特征作为最优特征
for i in range(len(labels)):
tmpClassifyData = {}
# 取出第i个特征的所有可能值
valueAll = [man[i] for man in data]
valueSetAll = set(valueAll) # 去重后的所有可能特征值
# 循环计算按各个可能值分类后的熵,然后求期望
classifyShannonMean = 0
for value in valueSetAll:
resData = categorizationOfData(i, value, data) # 按该特征值分类后结果
classifyShannon = calcShannon(resData) # 分类后的熵
classifyShannonMean += (valueAll.count(value) / len(valueAll)) * classifyShannon # 期望
tmpClassifyData.update({value: resData})
# 计算按照当前特征分类后的熵差
diff = originalShannon - classifyShannonMean
if diff >= diffShannon:
bestFeatureIndex = i
bestClassifyData = tmpClassifyData
diffShannon = diff
# 按结果分类,把labels中的最优特征删去,构建节点,并将各结果数据集递归
bestFeature = labels[bestFeatureIndex] # 获取最优特征的中文描述
tmpLabels = labels[:]
tmpLabels.pop(bestFeatureIndex)
node = {bestFeature: {}} # 当前节点
for key in bestClassifyData:
resClassify = createTree(bestClassifyData[key], tmpLabels)
node[bestFeature].update({key: resClassify})
return node # 使用样本测试样本构建决策树
tree = createTree(data, labels)
# 打印树
print(tree)
# 得到结果:{'是否戴眼镜': {'有眼镜': {'身材': {'胖': {'头发长短': {'长发': '男', '短发': '女'}}, '瘦': '女'}}, '没眼镜': '男'}}

(ps:不知不觉已经是第100篇随笔了,还是很有成就感的^_^)

D3算法编写决策树的更多相关文章

  1. SparkMLlib回归算法之决策树

    SparkMLlib回归算法之决策树 (一),决策树概念 1,决策树算法(ID3,C4.5 ,CART)之间的比较: 1,ID3算法在选择根节点和各内部节点中的分支属性时,采用信息增益作为评价标准.信 ...

  2. (ZT)算法杂货铺——分类算法之决策树(Decision tree)

    https://www.cnblogs.com/leoo2sk/archive/2010/09/19/decision-tree.html 3.1.摘要 在前面两篇文章中,分别介绍和讨论了朴素贝叶斯分 ...

  3. SparkMLlib分类算法之决策树学习

    SparkMLlib分类算法之决策树学习 (一) 决策树的基本概念 决策树(Decision Tree)是在已知各种情况发生概率的基础上,通过构成决策树来求取净现值的期望值大于等于零的概率,评价项目风 ...

  4. 机器学习中的算法(1)-决策树模型组合之随机森林与GBDT

    版权声明: 本文由LeftNotEasy发布于http://leftnoteasy.cnblogs.com, 本文可以被全部的转载或者部分使用,但请注明出处,如果有问题,请联系wheeleast@gm ...

  5. paper 56 :机器学习中的算法:决策树模型组合之随机森林(Random Forest)

    周五的组会如约而至,讨论了一个比较感兴趣的话题,就是使用SVM和随机森林来训练图像,这样的目的就是 在图像特征之间建立内在的联系,这个model的训练,着实需要好好的研究一下,下面是我们需要准备的入门 ...

  6. ID3算法(决策树)

    一,预备知识: 信息量: 单个类别的信息熵: 条件信息量: 单个类别的条件熵: 信息增益: 信息熵: 条件熵:(表示分类的类,表示属性V的取值,m为属性V的取值个数,n为分类的个数) 二.算法流程: ...

  7. python数据分析算法(决策树2)CART算法

    CART(Classification And Regression Tree),分类回归树,,决策树可以分为ID3算法,C4.5算法,和CART算法.ID3算法,C4.5算法可以生成二叉树或者多叉树 ...

  8. python 数据分析算法(决策树)

    决策树基于时间的各个判断条件,由各个节点组成,类似一颗树从树的顶端,然后分支,再分支,每个节点由响的因素组成 决策树有两个阶段,构造和剪枝 构造: 构造的过程就是选择什么属性作为节点构造,通常有三种节 ...

  9. 机器学习(Machine Learning)算法总结-决策树

    一.机器学习基本概念总结 分类(classification):目标标记为类别型的数据(离散型数据)回归(regression):目标标记为连续型数据 有监督学习(supervised learnin ...

随机推荐

  1. 使用pynlpir增强jieba分词的准确度

    在使用jieba分词时,发现分词准确度不高.特别是一些专业词汇,比如堡垒机,只能分出堡垒,并不能分出堡垒机.这样导致的问题是很多时候检索并不准确. 经过对比测试,发现nlpir进行分词效果更好.但是n ...

  2. 2018年-2019年第二学期第七周C#学习个人总结

    在本周我又学习了,第五章面向对象高级中的5.5异常和5.6命名空间和程序集.在5.5异常中我知道了异常层次结构:所有的异常类都继承自Exception类.由于发生了异常程序立即终止无法再继续向下执行. ...

  3. 王之泰201771010131《面向对象程序设计(java)》第十四周学习总结

    第一部分:理论知识学习部分 第12章 Swing用户界面组件 12.1.Swing和MVC设计模式 a 设计模式初识b 模型—视图—控制器模式c Swing组件的模型—视图—控制器分析 12.2布局管 ...

  4. SPOJ 10570 LONGCS - Longest Common Substring

    思路 和SPOJ 1812 LCS2 - Longest Common Substring II一个思路,改成多组数据就有三倍经验了 代码 #include <cstdio> #inclu ...

  5. jenkins 配置

    配置: echo " aliyun.oss.access.key=LTAIz4Koeff8sCr8 " > ./src/main/resources/oss.dev.prop ...

  6. enum & json 之间的转换

    enum 转为 string:EnumMember & StringEnumConverter public enum CampaignStatus : Int32 { [EnumMember ...

  7. javaScript--animate函数

    一.思路 1.获取目标值 2.再获取初始值 3.得到总距离 4.定义定时器的执行间隔 5.获取时间 6.得到总次数 7.总距离/总次数 = 步长 8.使用setInterval不停地改变dom元素的每 ...

  8. Oracle 并发创建索引

    建索引时,我们为了建索引快,会加上并行,加上并行之后,此列索引就会是并行了.访问有并行度的索引时,CBO可能可能会考虑并行执行,这可能会引发一些问题,如在服务器资源紧张的时候用并行会引起更加严重的争用 ...

  9. 如何系统地自学 Python?

    最近开始系统的学习Python,以及整理的一些资料.github记录着个人自学 Python 的过程,持续更新.欢迎大家一起来完善这个自学Python学习的项目,给后来者一个参考的学习过程.githu ...

  10. vue项目使用element ui的Checkbox

    最近使用到element ui的下拉多选框Checkbox Checkbox用法可参考与于 http://element.eleme.io/#/zh-CN/component/checkbox Che ...