id3算法c
① 决策树原理及算法比较
决策树是什么?
和线性回归一样是一种模型,内部节点和叶节点。实现分类,内部节点和叶节点通过有向线(分类规 则)连接起来
决策树的目标是什么?
决策树通过对数据复杂度的计算,建立特征分类标准,确定最佳分类特征。
表现为“熵”(entropy)和信息增益(information gain),基于决策树思想的三种算法:ID3,C4.5,CART算法,三种算法的信息衡量的指标也不同.
熵来表示信息的复杂度,熵越大,信息也就越复杂,公式如下:
那些算法能够实现决策树?
在决策树构建过程中,什么是比较重要的。特征选择(按照熵变计算),算法产生最重要的部分,
决策树中叶节点的分类比较纯,
节点顺序的排列规则:
熵变:
数据的预处理:
改进思路一般有两个1,换算法;2,调参数
做好数据的预处理:
1,做好特征选择;
2,做好数据离散化、异常值处理、缺失填充
分类器:
在决策树中,从根到达任意一个叶节点的之间最长路径的长度,表示对应的算法排序中最坏情况下的比较次数。这样一个比较算法排序中的最坏情况的比较次数就与其决策树的高度相同,同时如果决策树中每种排列以可达叶子的形式出现,那么关于其决策树高度的下界也就是关于比较排序算法运行时间的下界,
ID3算法存在的缺点:
1,ID3算法在选择根节点和内部节点分支属性时,采用信息增益作为评价标准。信息增益的缺点是倾向于选择取值较多的属性
2,当数据为连续性变量的时候,ID3算法就不是一个合理的算法的模型了
C4.5信息增益比率,
1,在信息增益的基础上除以split-info,是将信息增益改为信息增益比,以解决取值较多的属性的问题,另外它还可以处理连续型属性,其判别标准是θ,
2,C4.5算法利用增益/熵值,克服了树生长的过程中,总是‘贪婪’选择变量分类多的进行分类
3,处理来内需型变量,C4.5的分类树的分支就是两条
衡量指标:
(1)信息增益
基于ID3算法的信息增益对于判定连续型变量的时候病不是最优选择,C4.5算法用了信息增益率这个概念。
分类信息类的定义如下:
这个值表示将训练数据集D划分成对应属性A测试的V个输出v个划分产生的信息,信息增益率定义为:
选择最大信息增益率的属性作为分裂属性
Gini指标,CART
表明样本的“纯净度”。Gini系数避免了信息增益产生的问题,
过拟合问题,非常好的泛化能力,有很好的推广能力
Gini系数的计算:
在分类问题中,假设有k个类,样本点属于第k类的概率为Pk,则概率分布的gini指数的定义为:
如果样本集合D根据某个特征A被分割为D1,D2两个部分,那么在特征A的提哦啊见下,集合D的gini指数的定义为:
Gini指数代表特征A不同分组下的数据集D的不确定性,gini指数越大,样本集合的不确定性也就越大,这一点和熵的概念相类似
决策树原理介绍:
第三步:对于每个属性执行划分:
(1)该属性为离散型变量
记样本中的变量分为m中
穷举m种取值分为两类的划分
对上述所有划分计算GINI系数
(2)该属性为连续型变量
将数据集中从小到大划分
按顺序逐一将两个相临值的均值作为分割点
对上述所有划分计算GINI系数
学历的划分使得顺序的划分有个保证,化为连续型变量处理。
决策树的生成算法分为两个步骤:
预剪枝和后剪枝 CCP(cost and complexity)算法:在树变小和变大的的情况有个判断标准。误差率增益值:α值为误差的变化
决策树的终止条件:
1,某一个节点的分支所覆盖的样本都是同一类的时候
2,某一个分支覆盖的样本的个数如果小于一个阈值,那么也可以产生叶子节点,从而终止Tree-Growth
确定叶子结点的类:
1,第一种方式,叶子结点覆盖的样本都属于同一类
2, 叶子节点覆盖的样本未必是同一类,所占的大多数,那么该叶子节点的类别就是那个占大多数的类
② 【理论篇】决策树算法 - 信息增益率、GINI系数
ID3 决策树算法在特征选择时存在什么问题呢?
我们来举个例子:数据集 A 存在一个非常稀疏的特征 ID 列,我们知道 ID 是唯一不重复的,种类自然就会非常庞大。
这个时候,如果我们使用 ID 去切分数据集,那切分到最后,每个样本都会被分配到单独的样子结点上,每个样子结点的数据只有一样,不确定性为 0 ,熵值也为 0 。
那这样是不是就说名 ID 这个特征非常好呢?根据 ID 就能预测标签?当然不是,实际上 ID 这个特征毫无意义。
小鱼这里拿 ID 举例,只是个极端的例子。但足以说明,对于类似 ID 这样数据种类非常多,分布非常稀疏的特征来说,ID3 决策树算法通过信息增益来选取结点特征是远远不够的。
为了解决 ID3 决策树算法的问题,我们引入了信息增益率,计算信息增益时,考虑特征分布的自身熵。
C4.5 决策树算法使用信息增益率来衡量特征节点的分类能力。所谓信息增益率就是在信息增益的基础上除以该特征自身的熵值计算而来。
为什么要除以特征自身的熵值呢?我们举个例子:还是刚才的 ID 特征,ID 特征切分完数据后的熵值为 0 ,原始数据集的熵值为 G,特征 ID 的熵值为 -n*(1/n)*log(1/n) = -log(1/n) 其中 n 为数据集样本的个数。因此,特征 ID 的熵 G2 是一个非常庞大的数值。
使用 ID 节点切分数据集之后,得到的信息增益为:G - 0 = G,信息增益非常大,分类效果堪称完美。但如果使用信息增益率去衡量,则:(G - 0)/G2,其中 G2 一定是远远大于 G 的,因为很显然标签的混乱层度远低于 ID 列的混乱层度。
因此,我们求得的信息增益率就是一个非常小的值了,这个时候就可以发现 ID 这个特征分类效果非常差。也因此 C4.5 算法很好地解决了 ID3 算法对稀疏特征衡量的不足。
GINI 系数和熵的衡量标准类似,只是计算方式不同。GINI 系数的公式为:
当概率 P 为 0 或者 1 时,此时没有不确定性。其中概率为 1 时,GINI系数为 0 ,概率为 0 时,GINI 系数也为 0 。
③ C4.5算法
C4.5是一系列用在机器学习和数据挖掘的分类问题中的算法。它的目标是监督学习:给定一个数据集,其中的每一个元组都能用一组属性值来描述,每一个元组属于一个互斥的类别中的某一类。C4.5的目标是通过学习,找到一个从属性值到类别的映射关系,并且这个映射能用于对新的类别未知的实体进行分类。
C4.5由J.Ross Quinlan在ID3的基础上提出的。ID3算法用来构造决策树。决策树是一种类似流程图的树结构,其中每个内部节点(非树叶节点)表示在一个属性上的测试,每个分枝代表一个测试输出,而每个树叶节点存放一个类标号。一旦建立好了决策树,对于一个未给定类标号的元组,跟踪一条有根节点到叶节点的路径,该叶节点就存放着该元组的预测。决策树的优势在于不需要任何领域知识或参数设置,适合于探测性的知识发现。
决策树呈树形结构,在分类问题中,表示基于特征对实例进行分类的过程。学习时,利用训练数据,根据损失函数最小化的原则建立决策树模型;预测时,对新的数据,利用决策模型进行分类。
决策树是一种通过对特征属性的分类对样本进行分类的树形结构,包括有向边以及三类节点:
上图给出了(二叉)决策树的示例。决策树具有以下特点:
决策树学习的本质是从训练集中归纳出一组分类规则。但随着分裂属性次序的不同,所得到的决策树也会不同。如何得到一棵决策树既对训练数据有较好的拟合,又对未知数据有很好的预测呢?
首先,我们要解决两个问题:
一般的,一颗决策树包含一个根节点、若干个内部结点和若干个叶结点;叶结点则对应于一个属性册书;每个叶结点包含的样本集合根据属性测试的结果被划分到子结点中;根结点包含样本全集,从根结点到每个叶结点的路径对饮过了一个判定测试序列。决策树学习的目的是为了产生一颗泛化能力强的决策树,其基本流程遵循简单且只管的“分而治之”(divide-and-conquer)策略,如下图所示:
显然,决策树的生成是一个递归的过程。在决策树基本算法中,有三种情形会导致递归返回:
在第二种情形下,我们把当前结点标记为叶结点,并且将其类别设定为该结点所含样本最多的类别;在第三种情形下,同样把当前结点标记为叶结点,但将其类别设定为其父结点所含样本最多类别。注意这两种情形的处理实质不同:情形二是在利用当前结点的后验分布,而情形三则是把父结点的样本分布当做当前结点的先验分布。
决策树学习的关键在于如何选择最优划分属性。一般而言,随着划分过程的不断进行,我们希望决策树的分支结点所包含的样本尽可能属于同一类别,即结点的“纯度”越来越高。
“信息熵”(information entropy)是度量样本集合纯度最常用的一种指标。假定当前样本集合 中第k类样本所占比例为 ,则 的信息熵定义为
的值越小,则 的纯度越高。
假定离散属性 有 个可能的取值 ,若使用 来对样本集合 进行划分,则会产生 个分支结点,其中第v个分支结点包含了 中所有在属性 上取值为 的样本,记为 ,我们根据上述公式计算出 的信息熵,再考虑到不同的分支结点所包含的样本数不同,给分支结点赋予权重 ,即样本越多的分支结点影响越大,于是可以计算出用属性 对样本集合 进行划分所获得的"信息增益"(information gain)
一般而言,信息增益越大,则意味着使用属性a来进行划分所获得的“纯度提升越大”。因此,我们可用信息增益来进行决策树的划分属性选择。
实际上,信息增益准则对可取值数目较多的属性有所偏好(如何以序号作为划分属性,每一个事物作为一个单独存在的类别的时候,信息增益往往会很高,但是这样进行划分并没有什么意义),为了减少这种偏好可能带来的不利影响,着名的C4.5算法并不是直接使用信息增益,而是使用增益率(gain ratio)来选择最优的划分属性。增益率的定义为:
值得注意的是: 增益率准则对可取值数目较少的属性有所偏好,因此C4.5算法并不是直接选择增益率最大的候选划分属性,而是使用了一个启发式: 先从候选划分属性中找出信息增益高于平均水平的属性,再从中选择增益率最高的
CART决策树使用“基尼指数”来选择划分属性。数据集 的纯度可用基尼值来度量:
直观来说, 反映了从数据集 中随机抽取两个样本,其类别标记不一致的概率,因此 值越小,则数据集 的纯度就越高。属性 的基尼指数定义为:
于是,我们在候选属性集合 中,选择那个使得划分后基尼指数最小的属性作为最优划分属性,即
银行希望能够通过一个人的信息(包括职业、年龄、收入、学历)去判断他是否有贷款的意向,从而更有针对性地完成工作。下表是银行现在能够掌握的信息,我们的目标是通过对下面的数据进行分析建立一个预测用户贷款一下的模型。
上表中有4个客户的属性,如何综合利用这些属性去判断用户的贷款意向?决策树的做法是每次选择一个属性进行判断,如果不能得出结论,继续选择其他属性进行判断,直到能够“肯定地”判断出用户的类型或者是上述属性都已经使用完毕。比如说我们要判断一个客户的贷款意向,我们可以先根据客户的职业进行判断,如果不能得出结论,再根据年龄作判断,这样以此类推,直到可以得出结论为止。决策树用树结构实现上述的判断流程,如图所示:
以熵作为节点复杂度的统计量,分别求出下面例子的信息增益,图3.1表示节点选择属性1进行分裂的结果,图3.2表示节点选择属性2进行分裂的结果,通过计算两个属性分裂后的信息增益,选择最优的分裂属性。
属性一
属性二
由于 ,所以属性1是比属性2更优的分裂属性,故而选择属性1作为分裂属性。
由于 ,故而选择属性2作为分裂属性。
剪枝(pruning)是决策树学习算法对付“过拟合”的主要手段。在决策树学习中,为了尽可能正确分类训练样本,结点划分过程将不断重复,有事会造成决策树分支过多,这是就可能因为训练样本学得太好了,以致把训练集自身的一些特点党组哟所有数据都具有的一般性质而导致过拟合。因此,可通过主动去掉一些分支来降低过拟合的风险。
其中{1,2,3,6,7,10,14,15,16,17}为测试集,{4,5,8,9,11,12,13}为训练集。
预剪枝是要对划分前后泛化性能进行评估。对比决策树某节点生成前与生成后的泛化性能。
2.计算训练集的信息增益,得知脐部的信息增益最大,因此按照脐部进行划分。又因为在训练集中,凹陷特征好瓜的占比多,因此凹陷划分为好瓜,稍凹特征好过占比多,因此将其标记为好瓜,因此按照脐部划分的子树结果如下:
划分后,对比结果如下:
由图可知,预剪枝使得很多分支没有展开,这不仅降低了过拟合的风险,还显着减少了决策树的训练时间开销和测试时间。但是,有些分支虽当前不能提升泛化性。甚至可能导致泛化性暂时降低,但在其基础上进行后续划分却有可能导致显着提高,因此预剪枝的这种贪心本质,给决策树带来了欠拟合的风险。
后剪枝表示先从训练集中生成一颗完整决策树。
对比标记节点的划分类与各数据的真实分类,计算准确率,如下表所示:
生成的决策树,在验证集上的准确度为3/7*100%=42.9%.
对比预剪枝与后剪枝生成的决策树,可以看出,后剪枝通常比预剪枝保留更多的分支,其欠拟合风险很小,因此后剪枝的泛化性能往往由于预剪枝决策树。但后剪枝过程是从底往上裁剪,因此其训练时间开销比前剪枝要大。
④ 决策树算法的典型算法
决策树的典型算法有ID3,C4.5,CART等。
国际权威的学术组织,数据挖掘国际会议ICDM (the IEEE International Conference on Data Mining)在2006年12月评选出了数据挖掘领域的十大经典算法中,C4.5算法排名第一。C4.5算法是机器学习算法中的一种分类决策树算法,其核心算法是ID3算法。C4.5算法产生的分类规则易于理解,准确率较高。不过在构造树的过程中,需要对数据集进行多次的顺序扫描和排序,在实际应用中因而会导致算法的低效。
决策树算法的优点如下:
(1)分类精度高;
(2)生成的模式简单;
(3)对噪声数据有很好的健壮性。
因而是目前应用最为广泛的归纳推理算法之一,在数据挖掘中受到研究者的广泛关注。
⑤ 数据挖掘的十大经典算法,总算是讲清楚了,想提升自己的赶快收藏
一个优秀的数据分析师,除了要掌握基本的统计学、数据分析思维、数据分析工具之外,还需要掌握基本的数据挖掘思想,帮助我们挖掘出有价值的数据,这也是数据分析专家和一般数据分析师的差距所在。
国际权威的学术组织the IEEE International Conference on Data Mining (ICDM) 评选出了数据挖掘领域的十大经典算法:C4.5, k-Means, SVM, Apriori, EM, PageRank, AdaBoost, kNN, Naive Bayes, and CART.
不仅仅是选中的十大算法,其实参加评选的18种算法,实际上随便拿出一种来都可以称得上是经典算法,它们在数据挖掘领域都产生了极为深远的影响。今天主要分享其中10种经典算法,内容较干,建议收藏备用学习。
1. C4.5
C4.5算法是机器学习算法中的一种分类决策树算法,其核心算法是ID3算法. C4.5算法继承了ID3算法的优点,并在以下几方面对ID3算法进行了改进:
1) 用信息增益率来选择属性,克服了用信息增益选择属性时偏向选择取值多的属性的不足;
2) 在树构造过程中进行剪枝;
3) 能够完成对连续属性的离散化处理;
4) 能够对不完整数据进行处理。
C4.5算法有如下优点:产生的分类规则易于理解,准确率较高。其缺点是:在构造树的过程中,需要对数据集进行多次的顺序扫描和排序,因而导致算法的低效(相对的CART算法只需要扫描两次数据集,以下仅为决策树优缺点)。
2. The k-means algorithm 即K-Means算法
k-means algorithm算法是一个聚类算法,把n的对象根据他们的属性分为k个分割,k < n。它与处理混合正态分布的最大期望算法很相似,因为他们都试图找到数据中自然聚类的中心。它假设对象属性来自于空间向量,并且目标是使各个群组内部的均 方误差总和最小。
3. Support vector machines
支持向量机,英文为Support Vector Machine,简称SV机(论文中一般简称SVM)。它是一种监督式学习的方法,它广泛的应用于统计分类以及回归分析中。支持向量机将向量映射到一个更 高维的空间里,在这个空间里建立有一个最大间隔超平面。在分开数据的超平面的两边建有两个互相平行的超平面。分隔超平面使两个平行超平面的距离最大化。假定平行超平面间的距离或差距越大,分类器的总误差越小。一个极好的指南是C.J.C Burges的《模式识别支持向量机指南》。van der Walt 和 Barnard 将支持向量机和其他分类器进行了比较。
4. The Apriori algorithm
Apriori算法是一种最有影响的挖掘布尔关联规则频繁项集的算法。其核心是基于两阶段频集思想的递推算法。该关联规则在分类上属于单维、单层、布尔关联规则。在这里,所有支持度大于最小支持度的项集称为频繁项集,简称频集。
5. 最大期望(EM)算法
在统计计算中,最大期望(EM,Expectation–Maximization)算法是在概率(probabilistic)模型中寻找参数最大似然 估计的算法,其中概率模型依赖于无法观测的隐藏变量(Latent Variabl)。最大期望经常用在机器学习和计算机视觉的数据集聚(Data Clustering)领域。
6. PageRank
PageRank是Google算法的重要内容。2001年9月被授予美国专利,专利人是Google创始人之一拉里·佩奇(Larry Page)。因此,PageRank里的page不是指网页,而是指佩奇,即这个等级方法是以佩奇来命名的。
PageRank根据网站的外部链接和内部链接的数量和质量俩衡量网站的价值。PageRank背后的概念是,每个到页面的链接都是对该页面的一次投票, 被链接的越多,就意味着被其他网站投票越多。这个就是所谓的“链接流行度”——衡量多少人愿意将他们的网站和你的网站挂钩。PageRank这个概念引自 学术中一篇论文的被引述的频度——即被别人引述的次数越多,一般判断这篇论文的权威性就越高。
7. AdaBoost
Adaboost是一种迭代算法,其核心思想是针对同一个训练集训练不同的分类器(弱分类器),然后把这些弱分类器集合起来,构成一个更强的最终分类器 (强分类器)。其算法本身是通过改变数据分布来实现的,它根据每次训练集之中每个样本的分类是否正确,以及上次的总体分类的准确率,来确定每个样本的权 值。将修改过权值的新数据集送给下层分类器进行训练,最后将每次训练得到的分类器最后融合起来,作为最后的决策分类器。
8. kNN: k-nearest neighbor classification
K最近邻(k-Nearest Neighbor,KNN)分类算法,是一个理论上比较成熟的方法,也是最简单的机器学习算法之一。该方法的思路是:如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别。
9. Naive Bayes
在众多的分类模型中,应用最为广泛的两种分类模型是决策树模型(Decision Tree Model)和朴素贝叶斯模型(Naive Bayesian Model,NBC)。 朴素贝叶斯模型发源于古典数学理论,有着坚实的数学基础,以及稳定的分类效率。
同时,NBC模型所需估计的参数很少,对缺失数据不太敏感,算法也比较简单。理论上,NBC模型与其他分类方法相比具有最小的误差率。 但是实际上并非总是如此,这是因为NBC模型假设属性之间相互独立,这个假设在实际应用中往往是不成立的,这给NBC模型的正确分类带来了一定影响。在属 性个数比较多或者属性之间相关性较大时,NBC模型的分类效率比不上决策树模型。而在属性相关性较小时,NBC模型的性能最为良好。
10. CART: 分类与回归树
CART, Classification and Regression Trees。 在分类树下面有两个关键的思想。第一个是关于递归地划分自变量空间的想法(二元切分法);第二个想法是用验证数据进行剪枝(预剪枝、后剪枝)。在回归树的基础上的模型树构建难度可能增加了,但同时其分类效果也有提升。
参考书籍:《机器学习实战》
⑥ 用python实现红酒数据集的ID3,C4.5和CART算法
ID3算法介绍
ID3算法全称为迭代二叉树3代算法(Iterative Dichotomiser 3)
该算法要先进行特征选择,再生成决策树,其中特征选择是基于“信息增益”最大的原则进行的。
但由于决策树完全基于训练集生成的,有可能对训练集过于“依赖”,即产生过拟合现象。因此在生成决策树后,需要对决策树进行剪枝。剪枝有两种形式,分别为前剪枝(Pre-Pruning)和后剪枝(Post-Pruning),一般采用后剪枝。
信息熵、条件熵和信息增益
信息熵:来自于香农定理,表示信息集合所含信息的平均不确定性。信息熵越大,表示不确定性越大,所含的信息量也就越大。
设x 1 , x 2 , x 3 , . . . x n {x_1, x_2, x_3, ...x_n}x
1
,x
2
,x
3
,...x
n
为信息集合X的n个取值,则x i x_ix
i
的概率:
P ( X = i ) = p i , i = 1 , 2 , 3 , . . . , n P(X=i) = p_i, i=1,2,3,...,n
P(X=i)=p
i
,i=1,2,3,...,n
信息集合X的信息熵为:
H ( X ) = − ∑ i = 1 n p i log p i H(X) =- \sum_{i=1}^{n}{p_i}\log{p_i}
H(X)=−
i=1
∑
n
p
i
logp
i
条件熵:指已知某个随机变量的情况下,信息集合的信息熵。
设信息集合X中有y 1 , y 2 , y 3 , . . . y m {y_1, y_2, y_3, ...y_m}y
1
,y
2
,y
3
,...y
m
组成的随机变量集合Y,则随机变量(X,Y)的联合概率分布为
P ( x = i , y = j ) = p i j P(x=i,y=j) = p_{ij}
P(x=i,y=j)=p
ij
条件熵:
H ( X ∣ Y ) = ∑ j = 1 m p ( y j ) H ( X ∣ y j ) H(X|Y) = \sum_{j=1}^m{p(y_j)H(X|y_j)}
H(X∣Y)=
j=1
∑
m
p(y
j
)H(X∣y
j
)
由
H ( X ∣ y j ) = − ∑ j = 1 m p ( y j ) ∑ i = 1 n p ( x i ∣ y j ) log p ( x i ∣ y j ) H(X|y_j) = - \sum_{j=1}^m{p(y_j)}\sum_{i=1}^n{p(x_i|y_j)}\log{p(x_i|y_j)}
H(X∣y
j
)=−
j=1
∑
m
p(y
j
)
i=1
∑
n
p(x
i
∣y
j
)logp(x
i
∣y
j
)
和贝叶斯公式:
p ( x i y j ) = p ( x i ∣ y j ) p ( y j ) p(x_iy_j) = p(x_i|y_j)p(y_j)
p(x
i
y
j
)=p(x
i
∣y
j
)p(y
j
)
可以化简条件熵的计算公式为:
H ( X ∣ Y ) = ∑ j = 1 m ∑ i = 1 n p ( x i , y j ) log p ( x i ) p ( x i , y j ) H(X|Y) = \sum_{j=1}^m \sum_{i=1}^n{p(x_i, y_j)\log\frac{p(x_i)}{p(x_i, y_j)}}
H(X∣Y)=
j=1
∑
m
i=1
∑
n
p(x
i
,y
j
)log
p(x
i
,y
j
)
p(x
i
)
信息增益:信息熵-条件熵,用于衡量在知道已知随机变量后,信息不确定性减小越大。
d ( X , Y ) = H ( X ) − H ( X ∣ Y ) d(X,Y) = H(X) - H(X|Y)
d(X,Y)=H(X)−H(X∣Y)
python代码实现
import numpy as np
import math
def calShannonEnt(dataSet):
""" 计算信息熵 """
labelCountDict = {}
for d in dataSet:
label = d[-1]
if label not in labelCountDict.keys():
labelCountDict[label] = 1
else:
labelCountDict[label] += 1
entropy = 0.0
for l, c in labelCountDict.items():
p = 1.0 * c / len(dataSet)
entropy -= p * math.log(p, 2)
return entropy
def filterSubDataSet(dataSet, colIndex, value):
"""返回colIndex特征列label等于value,并且过滤掉改特征列的数据集"""
subDataSetList = []
for r in dataSet:
if r[colIndex] == value:
newR = r[:colIndex]
newR = np.append(newR, (r[colIndex + 1:]))
subDataSetList.append(newR)
return np.array(subDataSetList)
def chooseFeature(dataSet):
""" 通过计算信息增益选择最合适的特征"""
featureNum = dataSet.shape[1] - 1
entropy = calShannonEnt(dataSet)
bestInfoGain = 0.0
bestFeatureIndex = -1
for i in range(featureNum):
uniqueValues = np.unique(dataSet[:, i])
condition_entropy = 0.0
for v in uniqueValues: #计算条件熵
subDataSet = filterSubDataSet(dataSet, i, v)
p = 1.0 * len(subDataSet) / len(dataSet)
condition_entropy += p * calShannonEnt(subDataSet)
infoGain = entropy - condition_entropy #计算信息增益
if infoGain >= bestInfoGain: #选择最大信息增益
bestInfoGain = infoGain
bestFeatureIndex = i
return bestFeatureIndex
def creatDecisionTree(dataSet, featNames):
""" 通过训练集生成决策树 """
featureName = featNames[:] # 拷贝featNames,此处不能直接用赋值操作,否则新变量会指向旧变量的地址
classList = list(dataSet[:, -1])
if len(set(classList)) == 1: # 只有一个类别
return classList[0]
if dataSet.shape[1] == 1: #当所有特征属性都利用完仍然无法判断样本属于哪一类,此时归为该数据集中数量最多的那一类
return max(set(classList), key=classList.count)
bestFeatureIndex = chooseFeature(dataSet) #选择特征
bestFeatureName = featNames[bestFeatureIndex]
del featureName[bestFeatureIndex] #移除已选特征列
decisionTree = {bestFeatureName: {}}
featureValueUnique = sorted(set(dataSet[:, bestFeatureIndex])) #已选特征列所包含的类别, 通过递归生成决策树
for v in featureValueUnique:
FeatureName = featureName[:]
subDataSet = filterSubDataSet(dataSet, bestFeatureIndex, v)
decisionTree[bestFeatureName][v] = creatDecisionTree(subDataSet, FeatureName)
return decisionTree
def classify(decisionTree, featnames, featList):
""" 使用训练所得的决策树进行分类 """
classLabel = None
root = decisionTree.keys()[0]
firstGenDict = decisionTree[root]
featIndex = featnames.index(root)
for k in firstGenDict.keys():
if featList[featIndex] == k:
if isinstance(firstGenDict[k], dict): #若子节点仍是树,则递归查找
classLabel = classify(firstGenDict[k], featnames, featList)
else:
classLabel = firstGenDict[k]
return classLabel
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
下面用鸢尾花数据集对该算法进行测试。由于ID3算法只能用于标称型数据,因此用在对连续型的数值数据上时,还需要对数据进行离散化,离散化的方法稍后说明,此处为了简化,先使用每一种特征所有连续性数值的中值作为分界点,小于中值的标记为1,大于中值的标记为0。训练1000次,统计准确率均值。
from sklearn import datasets
from sklearn.model_selection import train_test_split
iris = datasets.load_iris()
data = np.c_[iris.data, iris.target]
scoreL = []
for i in range(1000): #对该过程进行10000次
trainData, testData = train_test_split(data) #区分测试集和训练集
featNames = iris.feature_names[:]
for i in range(trainData.shape[1] - 1): #对训练集每个特征,以中值为分界点进行离散化
splitPoint = np.mean(trainData[:, i])
featNames[i] = featNames[i]+'<='+'{:.3f}'.format(splitPoint)
trainData[:, i] = [1 if x <= splitPoint else 0 for x in trainData[:, i]]
testData[:, i] = [1 if x <= splitPoint else 0 for x in testData[:, i]]
decisionTree = creatDecisionTree(trainData, featNames)
classifyLable = [classify(decisionTree, featNames, td) for td in testData]
scoreL.append(1.0 * sum(classifyLable == testData[:, -1]) / len(classifyLable))
print 'score: ', np.mean(scoreL)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
输出结果为:score: 0.7335,即准确率有73%。每次训练和预测的准确率分布如下:
数据离散化
然而,在上例中对特征值离散化的划分点实际上过于“野蛮”,此处介绍一种通过信息增益最大的标准来对数据进行离散化。原理很简单,当信息增益最大时,说明用该点划分能最大程度降低数据集的不确定性。
具体步骤如下:
对每个特征所包含的数值型特征值排序
对相邻两个特征值取均值,这些均值就是待选的划分点
用每一个待选点把该特征的特征值划分成两类,小于该特征点置为1, 大于该特征点置为0,计算此时的条件熵,并计算出信息增益
选择信息使信息增益最大的划分点进行特征离散化
实现代码如下:
def filterRawData(dataSet, colIndex, value, tag):
""" 用于把每个特征的连续值按照区分点分成两类,加入tag参数,可用于标记筛选的是哪一部分数据"""
filterDataList = []
for r in dataSet:
if (tag and r[colIndex] <= value) or ((not tag) and r[colIndex] > value):
newR = r[:colIndex]
newR = np.append(newR, (r[colIndex + 1:]))
filterDataList.append(newR)
return np.array(filterDataList)
def dataDiscretization(dataSet, featName):
""" 对数据每个特征的数值型特征值进行离散化 """
featureNum = dataSet.shape[1] - 1
entropy = calShannonEnt(dataSet)
for featIndex in range(featureNum): #对于每一个特征
uniqueValues = sorted(np.unique(dataSet[:, featIndex]))
meanPoint = []
for i in range(len(uniqueValues) - 1): # 求出相邻两个值的平均值
meanPoint.append(float(uniqueValues[i+1] + uniqueValues[i]) / 2.0)
bestInfoGain = 0.0
bestMeanPoint = -1
for mp in meanPoint: #对于每个划分点
subEntropy = 0.0 #计算该划分点的信息熵
for tag in range(2): #分别划分为两类
subDataSet = filterRawData(dataSet, featIndex, mp, tag)
p = 1.0 * len(subDataSet) / len(dataSet)
subEntropy += p * calShannonEnt(subDataSet)
## 计算信息增益
infoGain = entropy - subEntropy
## 选择最大信息增益
if infoGain >= bestInfoGain:
bestInfoGain = infoGain
bestMeanPoint = mp
featName[featIndex] = featName[featIndex] + "<=" + "{:.3f}".format(bestMeanPoint)
dataSet[:, featIndex] = [1 if x <= bestMeanPoint else 0 for x in dataSet[:, featIndex]]
return dataSet, featName
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
重新对数据进行离散化,并重复该步骤1000次,同时用sklearn中的DecisionTreeClassifier对相同数据进行分类,分别统计平均准确率。运行代码如下:
from sklearn.tree import DecisionTreeClassifier
import matplotlib.pyplot as plt
scoreL = []
scoreL_sk = []
for i in range(1000): #对该过程进行1000次
featNames = iris.feature_names[:]
trainData, testData = train_test_split(data) #区分测试集和训练集
trainData_tmp = .(trainData)
testData_tmp = .(testData)
discritizationData, discritizationFeatName= dataDiscretization(trainData, featNames) #根据信息增益离散化
for i in range(testData.shape[1]-1): #根据测试集的区分点离散化训练集
splitPoint = float(discritizationFeatName[i].split('<=')[-1])
testData[:, i] = [1 if x<=splitPoint else 0 for x in testData[:, i]]
decisionTree = creatDecisionTree(trainData, featNames)
classifyLable = [classify(decisionTree, featNames, td) for td in testData]
scoreL.append(1.0 * sum(classifyLable == testData[:, -1]) / len(classifyLable))
clf = DecisionTreeClassifier('entropy')
clf.fit(trainData[:, :-1], trainData[:, -1])
clf.predict(testData[:, :-1])
scoreL_sk.append(clf.score(testData[:, :-1], testData[:, -1]))
print 'score: ', np.mean(scoreL)
print 'score-sk: ', np.mean(scoreL_sk)
fig = plt.figure(figsize=(10, 4))
plt.subplot(1,2,1)
pd.Series(scoreL).hist(grid=False, bins=10)
plt.subplot(1,2,2)
pd.Series(scoreL_sk).hist(grid=False, bins=10)
plt.show()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
两者准确率分别为:
score: 0.7037894736842105
score-sk: 0.7044736842105263
准确率分布如下:
两者的结果非常一样。
(但是。。为什么根据信息熵离散化得到的准确率比直接用均值离散化的准确率还要低啊??哇的哭出声。。)
最后一次决策树图形如下:
决策树剪枝
由于决策树是完全依照训练集生成的,有可能会有过拟合现象,因此一般会对生成的决策树进行剪枝。常用的是通过决策树损失函数剪枝,决策树损失函数表示为:
C a ( T ) = ∑ t = 1 T N t H t ( T ) + α ∣ T ∣ C_a(T) = \sum_{t=1}^TN_tH_t(T) +\alpha|T|
C
a
(T)=
t=1
∑
T
N
t
H
t
(T)+α∣T∣
其中,H t ( T ) H_t(T)H
t
(T)表示叶子节点t的熵值,T表示决策树的深度。前项∑ t = 1 T N t H t ( T ) \sum_{t=1}^TN_tH_t(T)∑
t=1
T
N
t
H
t
(T)是决策树的经验损失函数当随着T的增加,该节点被不停的划分的时候,熵值可以达到最小,然而T的增加会使后项的值增大。决策树损失函数要做的就是在两者之间进行平衡,使得该值最小。
对于决策树损失函数的理解,如何理解决策树的损失函数? - 陶轻松的回答 - 知乎这个回答写得挺好,可以按照答主的思路理解一下
C4.5算法
ID3算法通过信息增益来进行特征选择会有一个比较明显的缺点:即在选择的过程中该算法会优先选择类别较多的属性(这些属性的不确定性小,条件熵小,因此信息增益会大),另外,ID3算法无法解决当每个特征属性中每个分类都只有一个样本的情况(此时每个属性的条件熵都为0)。
C4.5算法ID3算法的改进,它不是依据信息增益进行特征选择,而是依据信息增益率,它添加了特征分裂信息作为惩罚项。定义分裂信息:
S p l i t I n f o ( X , Y ) = − ∑ i n ∣ X i ∣ ∣ X ∣ log ∣ X i ∣ ∣ X ∣ SplitInfo(X, Y) =-\sum_i^n\frac{|X_i|}{|X|}\log\frac{|X_i|}{|X|}
SplitInfo(X,Y)=−
i
∑
n
∣X∣
∣X
i
∣
log
∣X∣
∣X
i
∣
则信息增益率为:
G a i n R a t i o ( X , Y ) = d ( X , Y ) S p l i t I n f o ( X , Y ) GainRatio(X,Y)=\frac{d(X,Y)}{SplitInfo(X, Y)}
GainRatio(X,Y)=
SplitInfo(X,Y)
d(X,Y)
关于ID3和C4.5算法
在学习分类回归决策树算法时,看了不少的资料和博客。关于这两个算法,ID3算法是最早的分类算法,这个算法刚出生的时候其实带有很多缺陷:
无法处理连续性特征数据
特征选取会倾向于分类较多的特征
没有解决过拟合的问题
没有解决缺失值的问题
即该算法出生时是没有带有连续特征离散化、剪枝等步骤的。C4.5作为ID3的改进版本弥补列ID3算法不少的缺陷:
通过信息最大增益的标准离散化连续的特征数据
在选择特征是标准从“最大信息增益”改为“最大信息增益率”
通过加入正则项系数对决策树进行剪枝
对缺失值的处理体现在两个方面:特征选择和生成决策树。初始条件下对每个样本的权重置为1。
特征选择:在选取最优特征时,计算出每个特征的信息增益后,需要乘以一个**“非缺失值样本权重占总样本权重的比例”**作为系数来对比每个特征信息增益的大小
生成决策树:在生成决策树时,对于缺失的样本我们按照一定比例把它归属到每个特征值中,比例为该特征每一个特征值占非缺失数据的比重
关于C4.5和CART回归树
作为ID3的改进版本,C4.5克服了许多缺陷,但是它自身还是存在不少问题:
C4.5的熵运算中涉及了对数运算,在数据量大的时候效率非常低。
C4.5的剪枝过于简单
C4.5只能用于分类运算不能用于回归
当特征有多个特征值是C4.5生成多叉树会使树的深度加深
————————————————
版权声明:本文为CSDN博主“Sarah Huang”的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_44794704/article/details/89406612
⑦ 决策树算法基础 ID3与C4.5
决策树算法基础:ID3与C4.5
设X是一个取有限个值得离散随机变量,其概率分布为P(X=xi)=pi, i=1,2,…,n。则随机变量X的信息熵为
条件熵H(Y|X)表示在已知随机变量X的条件下随机变量Y的不确定性。H(Y|X)的计算公式为
所以决策树分支后信息总熵H(D|A)=P1*H1+P2*H2+...+Pn*Hn,(特征A条件下D的经验条件熵)
所以信息增益ΔH=H(D)-H(D|A)
H(D|A)越小,ΔH越大,该特征A越适合作为当前的决策节点。
选取最佳特征伪代码:
计算信息总熵H(D)
遍历每一个特征下的关于D的经验条件熵H(D|A)
计算每一个特征的信息增益ΔH
将信息增益ΔH最大的特征作为最佳特征选为当前决策节点
ID3算法伪代码:
如果第一个标签的数量等于所有的标签数量,说明这是一个单节点树,返回这个标签作为该节点类
如果特征只有一个,说明这是一个单节点树,用多数表决法投票选出标签返回作为该节点类
否则,按信息增益最大的特征A作为当前决策节点,即决策树父节点
如果该特征的信息增益ΔH小于阈值,则用多数表决法投票选出标签返回作为该节点类
否则,对于该特征A的每一个可能值ai,将原空间D分割为若干个子空间Di
对于若干个非空子集Di,将每个Di中实例数最大的类作为标记,构建子节点
以Di为训练空间,递归调用上述步骤
由于信息增益存在偏向于选择取值较多的特征的问题,而C4.5算法中,将ID3算法里的信息增益换成信息增益比,较好地解决了这个问题。
决策树的优点在于计算量简单,适合有缺失属性值的样本,适合处理不相关的特征。而缺点是容易过拟合,可以通过剪枝来简化模型,另外随机森林也解决了这个问题。