感觉好久都没有写过程序了,一直上课没有时间。最近有点空,然后就写了下西瓜书中的决策树的实现。由于本人才疏学浅,采用的实现方式和数据结构可能不合理,没有考虑代码的复杂度和时间复杂度等等,仅写下自己的实现想法(大神们就打扰了)。该程序是基于C++语言来实现的,算法就是西瓜书上面的实现算法,采用最简单的ID3算法,用信息增益来选择最优划分,进而进行决策树的实现(没有对决策树进行剪枝操作,以后有时间再改进)。
1、基本概念
决策树的详细算法我就不介绍了,具体参看西瓜书。在这里,我想写一下算法的大体。首先说明一下属性、属性值、属性集、类别、训练集的概念。
1、属性:属性就是用来描述物体特征的量。比如:描述一个西瓜可以用色泽、根蒂、敲声、纹理、脐部、触感等等属性来说明一个西瓜是说明样子的。
2、属性值:属性值是属性的取值。比如:一个西瓜的色泽可以用青绿、乌黑、浅白来描述,这些就是西瓜的色泽属性的属性值。
3、属性集:属性集是物体所有属性的集合。顾名思义,就是上述列出的属性打包在一起组成的集合。
4、类别:物体的种类,决策树的目的就是根据属性来对物体进行分类。比如:西瓜有好瓜和坏瓜。
5、训练集:训练集就是样本集,所有的学习都需要通过数据来形成,决策树也是一样的。需要通过样本来形成一棵决策树。训练集必须包括物体各个属性的属性值和类别。
然后说明下算法的三种情况:
设训练集为D,属性集为A,需要生成树的节点。
1、若训练集D中的全部样本的类别都是一样的,比如都是好瓜或者都是坏瓜。这时候将节点的值标记为样本的类别。
2、若属性集A中的属性为空,即树的分支已经到底了,样本的所有属性已经用完,这时候需要将节点标记为叶节点。或者有训练集D中的所有样本,在属性集A上的取值是一样的。比如属性集A={色泽、根蒂、敲声},而训练集D={ {青绿、蜷缩、浊响、清晰、凹陷、硬滑、好瓜}、{青绿、蜷缩、浊响、稍糊、稍凹、软粘、好瓜}、{青绿、蜷缩、浊响、模糊、凹陷、软粘、坏瓜}},这时可以看出,训练集D在属性集A上的取值都为:青绿、蜷缩、浊响。这两种情况需要将节点标记为叶节点,叶节点的属性值为训练集中类别最多的类。如上述例子,就需要将叶节点标记为好瓜。
3、在第三步之前需要先从属性集A中选择一个最优划分属性a,如何选择最优属性a,下面再说明。
假设选择最优属性a的值的集合为{b1、b2、b3}。例如,假设选择的属性是a=色泽,而其对应的属性集为b={青绿、乌黑、浅白}。
这时候,我们需要对每个属性值从训练集D中划分出属性a的取值为b1(b2、b3)的子集c。例如,我们的训练集D={ {青绿、蜷缩、浊响、清晰、凹陷、硬滑、好瓜}、{青绿、蜷缩、浊响、稍糊、稍凹、软粘、好瓜}、{青绿、蜷缩、浊响、模糊、凹陷、软粘、坏瓜}},然后假设我们根据属性“纹理”=“凹陷”进行划分,则子集c={ {青绿、蜷缩、浊响、清晰、凹陷、硬滑、好瓜}、{青绿、蜷缩、浊响、模糊、凹陷、软粘、坏瓜}}。
然后产生一个节点,(1)若子集c为空,则将该节点标记为叶节点,标记的类别为训练集D中类别最多的类。(2)若c不为空,则将属性a从属性集A中剔除,将剩下的属性集合子集c,从第一步开始继续划分(即递归)。
下面说明最优属性a是如何划分的。首先是信息熵的概念,信息熵的定义如下:
其中,n为训练集D的类别数(如子集中的类别为好瓜、坏瓜,则n=2)。pk为第k个类别的样本在训练集中的比例。并规定若,则
。
有了信息熵就可以写出信息增益了,信息增益定义为:
其中,V为属性a的可能取值个数,Dv为属性a对应的属性值划分出来的训练子集(比如上面提到的c子集),D为训练集。
该算法划分最优属性a是根据信息增益来划分的,即信息增益越大,说明以a作为下一个属性来生成决策树最佳。
举个例子以便理解。
若训练集D={ {青绿 蜷缩 浊响 清晰 凹陷 硬滑 好瓜} {乌黑 蜷缩 沉闷 清晰 凹陷 硬滑 好瓜 } {青绿 蜷缩 沉闷 稍糊 稍凹 硬滑 坏瓜}},则n=2,信息熵为