决策树笔记:使用ID3算法
决策树笔记:使用ID3算法
决策树笔记:使用ID3算法
机器学习
先说一个偶然的想法:同样的一堆节点构成的二叉树,平衡树和非平衡树的区别,可以认为是“是否按照重要度逐渐降低”的顺序来分叉的。
其实这个也不一定局限于平衡树的解释。huffman编码就是这么干的:出现频率最高的编码一定是与root直接相连的,是层数最浅的。
什么是决策树
简单讲就是一棵多叉树,每个节点表示一个决策,它的不同分支表示依据决策结果划分的子类;子树要么仍然是决策数,要么是叶节点。叶节点表示原有label或某一个维度属性。
决策树算法,就是用训练数据构造一棵决策树,作为分类器,为测试数据使用。因此,决策树是一个学习的结果,是一个模型。
ID3算法是基于信息熵的决策树构造算法。假设你处于这样一个环境:你需要判断一个事物的类别,你只能通过问一系列问题来判断。显然,每次问的问题越有质量,就越容易得到答案。什么样的问题算有质量?能最大限度获取信息、使得你能缩小猜测范围,这样的问题是有质量的问题。这个过程持续进行,直到猜到该事物的分类。
在猜测过程中,所谓“尽可能缩小分类范围”,也就是每次得到尽可能多的信息。信息论中,使用信息熵表示不确定程度,信息熵越大,越不确定;信息熵越小,信息越多,事物越确定。因此,每一次决策都试图去获得最大的信息熵负增量,就是获得越多的信息。so,每一次决策时,我怎么知道信息熵是多少?
比如用于训练的向量形如(a,b,c,label),那么我我依次用a、b、c属性节点做决策,看看使用这个属性后,我能得到信息熵负增量是多少。比较每一个决策点,选一个最大值作为本次决策节点。
设pi表示事件i出现的概率,依据信息论可知,信息熵等于
信息熵公式的证明
这个公式的证明似乎没有什么用处,看看就好。通过阅读Shannon那篇A Mathematical Theory of Communication的附录2不难推出。
考虑如下情形:你需要确定下一件发生的事件,然而你只知道每一个事件发生的概率:p1,p2,...,pn。用H表示本次决策的熵。我们的决策基于如下3个假设:
1. H在pi处连续
2. 若所有pi相等,即pi=1n,则H为n的严格增函数
3. 若某一个选择被打散,变为两次连续的选择,则原有H应等于各独立的H的权和。
个人认为假设3
最重要,也很难翻译准确,原文如下:
If a choice be broken down into two successive choices, the original H should be the weighted sum of the individual values of H.
例如
从左边的树状图转换到右边一个树状图,是后两个分支先合并在分离,原来的一次决策变为两次决策,才能确定后面两个节点:
其中\frac{1}{2}表示这个分支的概率。这个假设能用来把平面式的数据塑造为树状、有层次的数据,在后面起到重要作用。
公式A(sm)=mA(s)的证明
假设A(n)=H(1n,1n,...,1n),怎样证明A(sm)=mA(s)?
A(s)可以看作:root节点只有一层子节点,子节点一共有s个,每个子节点被选中的概率为1s。
A(sm)则可以看作:root节点只有一层子节点,子节点一共有sm个,每个子节点被选中的概率都是1sm。
如果把对于任意一个1sm概率事件的确定,从原有的一步分解为两步:先做1s再做1sm−1,那么熵值H的计算依据假设(3)
即可计算:通过把A(sm)的每sm−1个连续的分支搓成一股,下一股则为A(sm−1),得到:
公式A(t)=K log t的证明
取对数并除以n log s,有:
由假设2
A(n)对n严格增有:
同除nA(s):
由上面两个趋向于0的绝对值不等式有:
信息熵公式H(p1,...,pn)=−K∑(pi log pi)的证明
假设有n组事件,第i组有ni个事件,选中第ni的概率为pi。注意此时事件总数是∑ni而不是n。
此时确定下一个事件,有假设3
,可以先从n组事件中选出ni这一组,然后再从这ni个事件中选择一个。这第二次选择是等概率的。因此有:
由∑pi=1有:
决策树的构造
如果label只有一个,表示数据都是同一个类别的,那么不必构造。
如果使用完了所有特征,仍然不能将数据划分成仅包含唯一类别的分组,那么也要停止递归,转调用表决函数。
除此以外,首先将各维度进行比较,看选择哪一个维度进行分类能得到更多的信息熵。这样一来,会按照这一列重复元素作为同一个小组,这个小组递归地创建决策树。
为得到最大的信息熵负增量,要逐列计算信息熵。对每一列将重复元素作为一个小组,能算出这个小组的发生概率;累加这些概率与概率对数值的乘积,能算出该列的信息熵负增量。比较每一列的信息熵负增量,用类似打擂台的方式选出最大的那个,并记录对应的列序号。最后返回这个序号。
创建决策树:
def createTree(dataSet, labels):
"""
创建决策树
myTree变量存储这个结果
myTree中某一层的一个节点,key是特征向量对应的label,val为属于key类和不属于key类的两个子树
"""
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[:] #列表会按照引用方式传递,因此,为了保证不改变labels这个原始列表,使用新变量subLabels来作为参数
myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value), subLabels)
return myTree
选出最好的特征列序号:
def chooseBestFeatureToSplit(dataSet):
"""
选择最好的数据集划分方式
即:对除label外的每一列都进行计算,每一列能算出一个总的信息增量(信息熵增量的负值)。
信息增量最多的那一列,就是最好的划分列。
"""
numFeatures = len(dataSet[0])-1
baseEntropy = calcShannonEnt(dataSet)
bestInfoGain = 0.0
bastFeature = -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)
prob = len(subDataSet)/float(len(dataSet))
newEntropy += prob * calcShannonEnt(subDataSet)
infoGain = baseEntropy - newEntropy
if infoGain > bestInfoGain:
bestInfoGain = infoGain
bestFeature = i
return bestFeature
切分数据:将指定列中与指定value相等的向量筛选出,并将其去除了指定列得到的子矩阵返回:
def splitDataSet(dataSet, axis, value):
"""
扫描数据集(矩阵)的指定列(axis列),如果某个向量第axis列的值等于value
那么将去除这个value后的向量存储起来
每一行都这么处理,最后返回的是“axis列与value相等并且去除了axis列的矩阵”
也就是:按照value划分了一个类,返回这个类
"""
retDataSet=[]
for featVec in dataSet:
if featVec[axis] == value:
reducedFeatVec = featVec[:axis]
reducedFeatVec.extend(featVec[axis+1:])
#reducedFeatVec:去除axis列后的向量
retDataSet.append(reducedFeatVec)
return retDataSet
反倒是计算信息熵的最核心代码最容易:
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 #书上此行少了一个indent。
shannonEnt = 0.0
for key in labelCounts:
prob = float(labelCounts[key])/numEntries
shannonEnt -= prob*log(prob,2)
return shannonEnt
当决策树终于构建完毕,就需要用它来预测一个测试向量的分类了:
def classify(inputTree, featLabels, testVec):
"""
使用决策树的分类函数
"""
firstStr = inputTree.keys()[0]
secondDict = inputTree[firstStr]
featIndex = featLabels.index[firstStr]
for key in secondDict.keys():
if testVec[featIndex]==key:
if type(secondDict[key]).__name__=='dict':
classLabel = classify(secondDict[key], featLabels, testVec)
else:
classLabel=secondDict[key]
return classLabel
算法中可替换部件
度量系统无序程度
除了信息熵,也可以用Gini不纯度来做。
数据划分
这里采用ID3算法。也可以用二分法。
还有C4.5和CART算法可用。挖坑待填
决策树笔记:使用ID3算法的更多相关文章
- 决策树的基本ID3算法
一 ID3算法的大致思想 基本的ID3算法是通过自顶向下构造决策树来进行学习的.我们首先思考的是树的构造从哪里开始,这就涉及到选择属性进行树的构造了,那么怎样选择属性呢?为了解决这个问题,我们使用统 ...
- python数据分析算法(决策树2)CART算法
CART(Classification And Regression Tree),分类回归树,,决策树可以分为ID3算法,C4.5算法,和CART算法.ID3算法,C4.5算法可以生成二叉树或者多叉树 ...
- ID3算法Java实现
ID3算法java实现 1 ID3算法概述 1.1 信息熵 熵是无序性(或不确定性)的度量指标.假如事件A的全概率划分是(A1,A2,...,An),每部分发生的概率是(p1,p2,...,pn).那 ...
- 深入了解机器学习决策树模型——C4.5算法
本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是机器学习专题的第22篇文章,我们继续决策树的话题. 上一篇文章当中介绍了一种最简单构造决策树的方法--ID3算法,也就是每次选择一个特 ...
- 决策树--ID3 算法(一)
Contents 1. 决策树的基本认识 2. ID3算法介绍 3. 信息熵与信息增益 4. ID3算法的C++实现 1. 决策树的基本认识 决策树是一种 ...
- 决策树ID3算法的java实现(基本试用所有的ID3)
已知:流感训练数据集,预定义两个类别: 求:用ID3算法建立流感的属性描述决策树 流感训练数据集 No. 头痛 肌肉痛 体温 患流感 1 是(1) 是(1) 正常(0) 否(0) 2 是(1) 是(1 ...
- 数据挖掘之决策树ID3算法(C#实现)
决策树是一种非常经典的分类器,它的作用原理有点类似于我们玩的猜谜游戏.比如猜一个动物: 问:这个动物是陆生动物吗? 答:是的. 问:这个动物有鳃吗? 答:没有. 这样的两个问题顺序就有些颠倒,因为一般 ...
- 决策树 -- ID3算法小结
ID3算法(Iterative Dichotomiser 3 迭代二叉树3代),是一个由Ross Quinlan发明的用于决策树的算法:简单理论是越是小型的决策树越优于大的决策树. 算法归 ...
- 机器学习笔记----- ID3算法的python实战
本文申明:本文原创,如有转载请申明.数据代码来自实验数据都是来自[美]Peter Harrington 写的<Machine Learning in Action>这本书,侵删. Hell ...
随机推荐
- bootstrap学习总结-js组件(四)
这次我们来看下js组件的使用,本篇文章会有点长,希望大家可以耐心看,相信收获会有不少.不少园友加我好友,表示喜欢我写文字的风格,简单明了,这里,再次谢谢你们的支持.一方面,博主自身技术有限,写的东西都 ...
- Oracle 排序中使用nulls first 或者nulls last 语法
-原理 Nulls first和nulls last是Oracle Order by支持的语法 如果Order by 中指定了表达式Nulls first则表示null值的记录将排在最前(不管是asc ...
- 013医疗项目-模块一:加入工具类ResultUtil
这篇文章要做的就是优化,封装.把之前的代码尽量封装进类,并且不要硬编码. 在UserServiceimpl中的insertSysuser()函数之前是这么写的: ResultInfo resultIn ...
- springmvc源码分析(转)
该博客转载自http://www.cnblogs.com/heavenyes/p/3905844.html#特在此说明!!!!! springmvc是一个基于spring的web框架.本篇文章对它的工 ...
- [资源]PHP使用消息队列
利用PHP操作Linux消息队列完成进程间通信 基于HTTP协议的轻量级开源简单队列服务:HTTPSQS[原创] Redis队列——PHP操作简单示例 入队操作 <?php $redis = n ...
- C#中的Decimal类型
这种类型又称财务类型,起源于有效数字问题.FLOAT 单精度,有效数字7位.有效数字是整数部分和小数部分加起来一共多少位.当使用科学计数法的,FLOAT型会出现很严重的错误.比如 8773234578 ...
- Linux非root用户安装jdk和tomcat
转载自:http://blog.csdn.net/wuyigong111/article/details/17410661,进行部分修改 创建一个用户 sgmm,并在其用户目录里面安装 jdk和tom ...
- IOS-一步一步教你自定义评分星级条RatingBar ——转载的
由于项目的需要,需要设计能评分.能显示评分数据的星级评分条,但是IOS上好像没有这个控件,Android是有RatingBar这个控件的(又发现一个IOS不如Android好的),那就只能自定义了,在 ...
- 关于json 与 Request Header 的Content-Type 一些关系。
由于最近遇到关于,ashx文件ajax解析参数的问题.查询网上很多资料后,已经解决. 鉴于网上已经足够多的,关于这个问题的文章.大部分内容来自互联网,我这里只是做一些整理和记录.特此说明并非原创. C ...
- $self $index $first $last parent() outerParent()
index5.html <html><head> <title>$self $index $first $last parent() outerParent()&l ...