一、概述
众所周知,决策树的引入是为了解决分类问题。提起决策树,很难不想到数据结构中的树。其实决策树就是一个树结构(二叉树或者非二叉树),如果把给定的一组样本数据构建成一棵决策树,那么叶子节点就是该组数据的分类结果,而非叶子节点呢就是样本数据的各个特征值,分支就是每个特征在其值域内的取值,现在脑海中是不是已经有一棵树状结构了呢。构造好的树我已经有画面了,那么问题来了,该如何去构建这棵树呢?
我们可以简单的把决策树的构建规则看作是if-then规则,我个人对if-then的理解就是if-elif-else。根据对不同的特征值做出不同的判断,从而采取不同的措施。张口就来——“构建一棵树决策树就完事了”,关键在于如何去构建呢?总不能就依次选择样本数据给的特征,然后按照树的形状排开吧,这也太暴力了。那么该如何去构建一棵能够很好拟合样本数据并且能够对新输入的数据做出很准确的分类的决策树呢?这正是本片博客想要讨论的。决策树的构建主要有ID3、C4.5、CART算法,其实三者都大同小异,主要是特征选择的方式不同,下面我就详细的讲讲特征选择。
二、特征选择
其实所谓的特征选择,听起来感觉高大上,其实不然。在我们着手解决特征选择之前,我需要引入几个跟“熵”有关的概念。
(1) 信息熵。
假设一个取值为离散值的随机变量的概率是,那么的熵就是,所要表示的意思就是一个随机变量的不确定性(纯度)。信息熵也被称作经验熵
样本数据集的信息熵的计算公式是: 其中是样本数据的总数,样本中一共有个类,||是某个类别的数量,那么就是某个类别的概率咯。
(2)条件熵。
类比条件概率的概念我们很容易理解,其实条件熵就是在整个样本数据的条件,每个特征(随机变量)的不确定性。同样的,条件熵也被称作经验条件熵。
特征A对数据集D的条件熵的计算公式: 其中是样本集的子集,是子集中分类结果为的样本数据。
(3)信息增益。
信息增益可以理解为某一个特征在得知某一条件之后,其不确定性减少的程度。
信息增益的计算公式: 即为集合的经验熵与特征给定条件下的经验条件熵的差值。
(4)信息增益比。
从名称也能看出,信息增益比是信息增益比上样本集关于特征的值的熵。
信息增益比的计算公式: 其中信息增益上式已求, 注意,此时的是特征取值的个数。
(5)基尼指数。
我们首先要知道分类问题中,概率分布的基尼指数的定义是:
其中 代表样本中类别数,是某个类别的概率。
我们引申到样本集合来,那基尼指数就是: 其中是样本集中第类的子集。
那么样本集合跟据特征是否取某一可能值被分割成,则在特征的条件下,集合的基尼指数是:
好了,弄清楚上面这些公式,就可以开始特征选择啦。决策树构造的好坏,即泛化能力的强弱也在此一举了。我们都知道每次选择一个特征作为节点,选择标注就显得很重要了,如何选择呢?
ID3算法看了上面几个概念,心里默念到,既然要构建的树稳定可靠,而信息增益能够很好的反应特征的纯度并且计算起来相对简单,那我选择信息增益作为我的特征选择标准吧。
C4.5算法狡猾的看了一ID3,选择信息增益的话,会很偏袒那些取值选择较多种类的特征啊!我选信息增益比作为我的特征选择标准。
CART算法想了一下,既然基尼指数也表示样本集合的不确定性,基尼指数越小代表样本数据集越稳定,那我选择基尼指数作为特征选择的标准好了。
至此,决策树生成最关键的部分已经解决了,ID3算法、C4.5算法和CART算法分别选择信息增益、信息增益比和基尼指数作为各自的特征选择标准。
三、python实现
我选用周志华老师的《机器学习》一书中的西瓜数据作为样本数据集。
dataset=[ ['青绿', '蜷缩', '浊响', '清晰', '凹陷', '硬滑', '好瓜'],
['乌黑', '蜷缩', '沉闷', '清晰', '凹陷', '硬滑', '好瓜'],
['乌黑', '蜷缩', '浊响', '清晰', '凹陷', '硬滑', '好瓜'],
['青绿', '蜷缩', '沉闷', '清晰', '凹陷', '硬滑', '好瓜'],
['浅白', '蜷缩', '浊响', '清晰', '凹陷', '硬滑', '好瓜'],
['青绿', '稍蜷', '浊响', '清晰', '稍凹', '软粘', '好瓜'],
['乌黑', '稍蜷', '浊响', '稍糊', '稍凹', '软粘', '好瓜'],
['乌黑', '稍蜷', '浊响', '清晰', '稍凹', '硬滑', '好瓜'],
['乌黑', '稍蜷', '沉闷', '稍糊', '稍凹', '硬滑', '坏瓜'],
['青绿', '硬挺', '清脆', '清晰', '平坦', '软粘', '坏瓜'],
['浅白', '硬挺', '清脆', '模糊', '平坦', '硬滑', '坏瓜'],
['浅白', '蜷缩', '浊响', '模糊', '平坦', '软粘', '坏瓜'],
['青绿', '稍蜷', '浊响', '稍糊', '凹陷', '硬滑', '坏瓜'],
['浅白', '稍蜷', '沉闷', '稍糊', '凹陷', '硬滑', '坏瓜'],
['乌黑', '稍蜷', '浊响', '清晰', '稍凹', '软粘', '坏瓜'],
['浅白', '蜷缩', '浊响', '模糊', '平坦', '硬滑', '坏瓜'],
['青绿', '蜷缩', '沉闷', '稍糊', '稍凹', '硬滑', '坏瓜'] ]
labels = ['色泽', '根蒂', '敲击', '纹理', '脐部', '触感']
由于本人代码能力差,所以代码很臃肿,就不一一展示,附上代码链接。
实现效果如下所示: