1. 引言
决策树(decision tree)是一种基本的分类和回归方法,由于其采用的是一种树形的结构,因此,具有很强的解释性和计算速度,也正是因为这些特点,使得决策树在很多行业都得到了应用,比如风控行业等。决策树的建模过程一般分为三个步骤:特征选择、决策树的生成和决策树的剪枝,根据这三个步骤所采用的规则,衍生出了很多不同的模型,比较经典的有Quinlan在1986年提出的ID3算法和1993年提出的C4.5算法,以及Breiman等人在1984年提出的CART算法,本文将以分类决策树为例,对这几个算法分别进行介绍,并用python进行实现。
2. 常用决策树模型介绍
2.1 决策树的定义
决策树是由结点和有向边组成的树形结构,其中,结点包含两种类型:内部结点和叶结点。内部结点表示一个特征或者属性,叶结点则表示一个类。如下图所示,其中每个圆圈表示内部结点,每个正方形表示叶结点。
对于给定的训练数据集,其中,表示输入的特征向量,为特征的个数,为类别标记,表示类别的个数,表示训练集的大小。决策树的思想大致如下:
- 首先,构建根结点,然后将整个训练集都放在根结点。
- 接着,从所有特征中选择一个最优特征,并根据该特征将训练数据集分割为多个子集,使得每一个子集有一个当前条件下的最好分类,如果某个子集已经基本分类正确,则将其作为叶结点,其对应的类别作为该叶结点的类别,否则,对每个子集继续选择最优的特征进行分割,如此递归下去,直到所有的子集基本被正确分类为止。最后,每个叶结点都代表一个子集,也是特征空间中的一个子区域,每个子区域之间都是不相交的。
- 最后,由于第二步为了将训练集划分正确,往往构建的决策树会过于庞大,这时,模型可能会出现过拟合,导致对新的测试数据可能分类效果不好,因此,需要对决策树自下而上进行剪枝,去掉一些过于细分的叶结点,使其回退到父结点或者更高的结点,然后将父结点或者更高的结点作为新的叶结点。
进行预测时,会根据决策树的分支情况,将实例划分到其归属的叶结点,并将该叶结点对应的类别作为实例的预测类别,从而达到分类的效果。下面,我们将根据决策树的三个步骤,对各个算法的思想进行介绍和对比。
2.2 ID3算法
适用场景:特征和目标变量都是离散型
2.2.1 特征选择——信息增益
特征选择是指决策树在每一次分支时,从所有的特征中选择能够对当前数据集具有最优分类能力的特征,这样可以提高模型的学习效率。ID3决策树的特征选择采用的是信息增益的方法。在介绍信息增益的概念之前,需要先介绍一下熵和条件熵的概念。
是一个取有限个值的离散随机变量,则其熵的计算公式如下:
其中,表示取某个类别时的概率,当时,定义,由于熵只依赖于的分布,因此,也可以将的熵记作,即
从熵的计算公式可以发现,当随机变量的不确定性越大时,熵的值会越大,其取值范围为:
的条件下随机变量的不确定性,其计算公式如下:
其中,。
的信息而使得类的信息的不确定性减少的程度。其计算公式如下:
当信息增益越大时,表示给定后,对进行分类后的不确定性越低,也就是说对的分类能力越强。因此,ID3在每一次分支时,采用信息增益作为每个结点特征选择的规则。
2.2.2 ID3决策树的构造
ID3算法构造决策树的思想大致如下:首先从根结点开始,对结点,对结点计算所有可能特征的信息增益,选择信息增益最大的特征作为结点的特征,由该特征的不同取值建立子结点,再对子结点递归地调用以上方法,构建决策树,直到所有特征的信息增益均很小或没有特征可以选择为止,最终得到一个决策树。其具体的算法步骤如下:
- 给定训练数据集,特征集,阈值;
- 若中所有实例属于同一类,则T为单结点树,并将类作为该结点的类标记,返回决策树;
- 若,则为单结点树,并将中实例数最大的类作为该结点的类标记,返回决策树;
- 否则,计算中各特征对的信息增益,选择信息增益最大的特征;
- 如果的信息增益小于阈值,则为单结点树,并将中实例数最大的类作为该结点的类标记,返回决策树;
- 否则,对的每一可能值,依将分割为若干非空子集,将中实例数最大的类作为标记,构建子结点,由结点及其子结点构成树,返回;
- 对第个子结点,以为训练集,以为特征集,递归地调用2~6步,得到子树,返回。
以上就是ID3决策树的构造过程,但是该过程构建的决策树往往会出现过拟合,因此,需要对树进行剪枝。
2.2.3 ID3决策树的剪枝
的,是树的某个叶结点,该叶结点有个样本点,其中类的样本点有个,,为叶结点上的经验熵,\alpha \geqslant 0为惩罚参数,则决策树的损失函数可以定义为:
其中,经验熵为:
将损失函数中的第一项记作:
则损失函数可以表达为:
其中,表示模型对训练数据的预测误差,即模型对训练数据的拟合程度,表示模型的复杂度,参数则表示惩罚参数,当越大时,则会选择越简单的树,反之,则选择较复杂的树。可以看出,决策树的剪枝不仅考虑模型的拟合程度,还考虑模型的复杂度,因此,相比决策树的构造过程,决策树的剪枝过程是一个全局优化的过程。决策树的剪枝步骤具体如下:
- 给定ID3算法生成的决策树,参数;
- 递归地从树的叶结点向上回缩,设一组叶结点回缩到其父结点之前与之后的整体树分别为与,其对应的损失函数值分别为与,如果,则进行剪枝,将其父结点变为新的叶结点。
- 重复步骤2,直到不能继续为止,此时得到损失函数最小的子树。
以上就是关于ID3算法的整个过程,下面介绍一个与ID3算法非常接近的决策树算法,即C4.5。
2.3 C4.5算法
适用场景:特征和目标变量都是离散型
2.3.1 特征选择——信息增益比
ID3选择的信息增益是一个绝对值的概念,对于不同的数据集,信息增益值往往不一样,对于分类问题困难时,其经验熵比较大,对应的信息增益值也会比较大,反之则比较小,因此,为了克服这个问题,C4.5对ID3算法的特征选择准则进行了改进。C4.5选取的特征选择准则是信息增益比,其定义就是将信息增益与训练数据集的经验熵之比,其计算公式如下:
2.3.2 C4.5决策树的构造
C4.5算法构造决策树的过程与ID3类似,只是将特征选择准则改为信息增益比,其他的都是一样的。
- 给定训练数据集,特征集,阈值;
- 若中所有实例属于同一类,则T为单结点树,并将类作为该结点的类标记,返回决策树;
- 若,则为单结点树,并将中实例数最大的类作为该结点的类标记,返回决策树;
- 否则,计算中各特征对的信息增益比,选择信息增益比最大的特征;
- 如果的信息增益比小于阈值,则为单结点树,并将中实例数最大的类作为该结点的类标记,返回决策树;
- 否则,对的每一可能值,依将分割为若干非空子集,将中实例数最大的类作为标记,构建子结点,由结点及其子结点构成树,返回;
- 对第个子结点,以为训练集,以为特征集,递归地调用2~6步,得到子树,返回。
2.3.3 C4.5决策树的剪枝
C4.5决策树的剪枝与ID3算法的一样,这里不再具体赘述。
2.4 CART算法
适用场景:支持数值型和离散型变量,支持分类和回归问题
2.4.1 特征选择——MSE或基尼指数
个类,样本点属于第类的概率为,则概率分布的基尼指数的定义为:
如果样本集合根据特征是否取某一可能值被分割成和两部分,即:
则在特征的条件下,集合的基尼指数定义为:
当基尼指数越大时,表示数据的不确定性越大,因此,CART分类树每次分支时,选择当前基尼指数最小的特征作为当前结点的特征选择。
2.4.2 CART决策树的构造
(一) 回归树的构造
与分别为输入和输出变量,并且是连续变量,给定训练数据集:
则回归树在每次分支时,会依次从特征集中选择第个变量和它取的值,作为切分变量和切分点,并定义两个区域:
然后计算两个区域中的均值分别作为两个区域的预测值和,接着,计算两个区域的平方误差和,并从中选择可以平方误差和最小的变量和切分点作为当前的最优切分变量和最优切分点,具体地,求解:
重复以上划分过程,直到满足停止条件为止,这样便形成了一棵回归树,这样的回归树通常称为最小二乘回归树。具体的算法步骤如下:
- 输入训练数据集;
- 遍历变量,求解:
确定使得上式达到最小值的最优切分变量和最优切分点; - 用选定的最小值对划分区域并决定相应的输出值:
- 继续对两个子区域调用步骤2、3,直至满足停止条件;
- 将输入空间h划分为区域,生成决策树:
(二) 分类树的构造
分类树则采用基尼指数选择最优特征,其算法步骤如下:
- 输入训练数据集D;
- 从根结点开始,计算现有特征取每个可能值时的基尼指数:
- 选择基尼指数最小的特征及其对应的切分点作为最优特征和最优切分点,依最优特征和最优切分点,从现结点生成两个子结点,将训练集依特征分配到两个子结点中去;
- 对两个子结点递归地调用步骤2、3,直至满足停止条件为止;
- 生成CART决策树。
2.4.3 CART决策树的剪枝
底端开始不断剪枝,直到的根结点,形成一个子树序列;接着,通过交叉验证法在独立验证集上对子树序列进行测试,从中选择最优子树。
从前面ID3算法我们可以知道,剪枝时的损失函数不仅考虑决策树对训练集的拟合程度,还考虑模型的复杂度,具体的公式如下:
CART首先从整体树开始剪枝,对的任意内部结点,以t为单结点树的损失函数是:
以为根结点的子树的损失函数是:
当时,即时,与有相同的损失函数值,而的结点少,因此比更可取,对进行剪枝。
中每一内部结点,计算:
在中减去最小的,将得到的子树作为,同时将最小的设为,为区间的最优子树,如此剪枝下去,直至根结点,在这一过程中,不断地增加值,产生新的区间。
最后,利用独立的验证数据集,测试子树序列中各棵子树的平方误差或基尼指数,平方误差或基尼指数最小的子树即为最优的决策树,其所在的区间即为最终的取值。具体的剪枝算法步骤如下:
- 给定CART算法生成的决策树,初始化k=0,
- 自下而上地对各内部结点计算,以及其中,表示以为根结点的子树,为对训练数据的预测误差,为叶结点个数。
- 自上而下地访问内部结点,如果有,则进行剪枝,并对叶结点以多数表决法决定其类,得到树;
- 设
- 如果不是由根结点单独构成的树,则回到步骤2
- 采用交叉验证法在子树序列中选取最优子树
3. 常用决策树模型的python实现
python中sklearn主要支持的是CART决策树,因为CART可适用的场景更广,不过,特征选择的准则sklearn也提供了两种选择,一种是“entropy”,对应本文介绍的信息增益,另一种是“gini”,对应本文的基尼指数,本文直接继承了sklearn.tree中的DecisionTreeClassifier,增加了对决策树的绘制函数,python绘制决策树需要安装graphviz,安装后如果出现中文乱码的话,可以参考这篇文章《graphviz Windows中文乱码》。具体的代码如下:
import os
from sklearn.tree import DecisionTreeClassifier, export_graphviz
class DecisionTreeClassifier(DecisionTreeClassifier):
def draw_tree(self, model, feature_names, save_path):
"""
绘制决策树
:param model: 决策树模型
:param feature_names: 结点名称. [list]
:param save_path: 文件保存路径
:return:
"""
# 生成决策树的路径dot文件,保存到save_path
export_graphviz(model, out_file=save_path,
feature_names=feature_names,
filled=True, rounded=True,
special_characters=True)
# 替换dot文件中的字体为Microsoft YaHei,以防止中文乱码
with open(save_path, 'r', encoding='utf-8') as f:
dot_data = f.read()
dot_data = dot_data.replace('fontname=helvetica', 'fontname="Microsoft YaHei"')
with open(save_path, 'w', encoding='utf-8') as f:
f.write(dot_data)
# 生成决策树图像,格式默认为png格式
os.system('dot -Tpng {0} -o {1}'.format(save_path, save_path.replace('dot', 'png')))
绘制的决策树图形大致如下:
具体的项目代码还是参考本人的github地址:
4. 总结
决策树由于其解释性强,计算速度快,非线性能力强,在一些对模型解释性强的行业得到了很多的应用,比如风控行业。另外,由于特征选择、决策树生成和决策树剪枝的不同,决策树衍生出了很多的算法,每个算法都有其对应的优缺点,因此,在使用时需要加以鉴别,比如ID3算法,由于不是二叉树的形式,因此该算法往往更倾向于选择类别多的特征。