ID3:归纳决策树(Induction Decision Tree Version 3)
ID3算法一种由数据构造递归的的过程。选择一个属性作为根节点,按照其他属性将数据集分类,每一个子节点得到一个数据集。对这种划分的质量进行评估,递归执行该过程,直至全部节点不能再进行划分。某节点不能划分的条件有2:一个是节点具有单类,二是节点具有单一属性。
质量评估的标准为:
①信息增益:根节点的信息值,与分裂子节点后各节点平均信息值的差
②信息增益率:信息增益有一个弊端,当例如ID码这种对分类结果没有任何用处,但是信息增益极大的属性,仅靠信息增益判断是不行的。
信息增益率 = 信息增益 / 节点的固有信息值(不考虑类,仅凭信息量)
虽然ID的信息增益率仍是最高的,但是他的优势已经大大减小了。在实际生产中,会相应处理掉ID码这种无用的属性。
以上是我认为ID3算法的应该注意的几个地方,下面着重分析weka的源码。
ID3算法的weka实现核心部分在建立树的部分,即makeTree()方法。前期有相关数据集的简单处理,相关作者文献信息等的处理,这里暂不介绍。
首先,Id3类要继承 AbstractClassifier:
有一些比较重要的成员变量:
①Id3[]成员变量是保存分类树的变量,数组的每一个元素都是当前结点的子结点
②m_Attribute变量保存结点进行分裂是基于的属性,即根据哪个属性分裂结点
③如果当前结点为叶子结点,则m_ClassValue变量代表当前结点的类别
④m_Distribution说明当前结点属于某种类别的概率
⑤m_ClassAttribute变量为数据集的类别
算法的入口为buildClassifier()方法,在其内部调用maketree()方法
其中getCapabilities().testWithFail(data)实际上是在数据的预处理之后,判断给定的数据集是否能被Id3处理。deleteWithMissingClass()是Instances类中的方法,作用是移除那些缺失某属性的实例(具体实现见Instances类),得到要求的实例集。
makeTree()是算法的核心所在。
首先计算最大信息增益
data.numAttributes()返回属性的个数,infoGains保存每一属性的信息增益值。
enumerateAttributes()是Instances类中的方法,作用是返回实例集的全部属性的集合类。
computeInfoGain(data, att)是实际计算信息增益值的函数。
最后将具有最大增益的属性赋值给m_Attribute,作为当前结点的分裂属性。
当某结点的信息增益为0时,此结点为叶子结点,不再分裂。
m_Attribute = null,已经为叶结点,分裂属性当然为null。由于m_Distribution保存类别的概率,data.numClasses()获得数据集的类别量。m_Distribution[(int) inst.classValue()]++,用于对属于各个类别的具体实例进行计数。
Utils.normalize()相当于归一化。m_ClassValue为叶子结点的类别,当然是概率最大的为其类别值。
如果不是叶结点,则要在分裂属性上将分裂当前结点。
splitData()为本类中的方法,分裂属性有多少属性值,就将数据集在当前结点分裂出多少棵子树,即:Instances[] splitData = new Instances[att.numValues()]。然后将将每一个新分裂出的数据集声明为足够大的集合类,详见Instances类中双参数的构造方法。
inst.value(att),取得属性的值,根据属性的值将各实例分配到分裂出的数据集中。最后compactify()用于调整集合类到最小容量。
最后将每一个m_Successors声明为一个Id3类,并递归调用执行makeTree(),将每一子树进行分裂,直至到全部叶结点,程序退出。