前言

所谓构建决策树,

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

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

熵的计算:熵计算的是数据集的纯净程度,数据集的熵的大小只和数据集中各数据样本的最终分类结果的分布有关。假设数据集中所有数据都是“同一种类”的数据,那么其熵就是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. Tomcat &servlet字符集编码问题

    1.字符编码的原由 1.1 request和response的默认编码是? 如果未指定字符编码,则Servlet规范要求使用ISO-8859-1的编码. HTTP消息正文(请求或响应)的字符编码在Co ...

  2. objectarx 把当前图形输出

    方法1: AcDbDatabase *pdb; acdbCurDwg()->wblock(pdb); pdb->saveAs(str); pdb->closeInput(true); ...

  3. AutoCAD2015有时候会显示乱七八糟的线

    问题描述:AutoCAD2015以上版本有时候打开一张图,会出现乱七八糟的线 解决方案: 这是由于硬件加速平滑线显示引起的,可以如下修改

  4. [java]第一个程序

    HelloWorld 主函数 学习一门语言第一部分就是学习主函数,Java的主函数是main函数有如下形式: public class HelloWorld{ public static void m ...

  5. 2019 年 GrapeCity Documents 产品路线图

    前言 | 问题背景 随着软件行业引入新的硬件和操作系统,我们看到更多的托管框架与.NET技术保持同步.Microsoft的.NET Standard和.NET Core定义了一个跨平台规范,为应用程序 ...

  6. Python链接Oracle数据库

    说明:以下所需安装的所有软件版本必须跟系统一致,即系统是64位,软件就得是64位,否则会出现各种链接报错的情况. 现以64位系统,python 3.6.5  64位为例: (一)安装cx_Oracle ...

  7. [原]osg模型动画|骨骼动画

    参考源码:osg的官方例子:osganimationviewer 首先制作一个带骨骼动画的模型  demo.FBX 这里面我们做了两个骨骼动画:1.open   2.close 下面开始在osg中使用 ...

  8. fiddler -- 一个强大的抓包工具

    一.fiddler常用功能: 1. Fiddler 是位于客户端和服务器端的http代理,也是目前最常用的http抓包工具之一.它能够记录客户端和服务器之间的所有http请求,可以针对特定的http请 ...

  9. python之做一个简易的翻译器(二)

    把写好的python程序转换为windows系统下可以运行的exe文件 使用pyinstaller命令来进行转换 1.首先安装pyinstaller 可以在pycharm中安装,也可以直接使用pip命 ...

  10. ubuntu1604 golang环境

    copy来的,这里记录一下 1. 升级系统: sudo apt-get upgrade 2. 安装docker 下载docker-ce: https://download.docker.com/lin ...