决策树(Decision Tree)是一种基本的分类与回归方法(ID3、C4.5和基于 Gini 的 CART 可用于分类,CART还可用于回归)。决策树在分类过程中,表示的是基于特征对实例进行划分,将其归到不同的类别。决策树的主要优点是模型可读、易于理解、分类速度快、建模与预测速度快。本文主要介绍 Quinlan 在 1986 年提出的 ID3 算法与 1993 年提出的 C4.5 算法。下面首先对决策树模型进行简单介绍。
决策树模型
决策树是由树节点与边组成的,其节点有两种类型,内部节点和叶节点,内部节点表示一个特征或者属性,叶节点代表类别,如下如所示:
图中可见根节点开始到叶节点的每条路径构建一条规则,内部节点的特征对应着规则的条件。整棵树满足一个重要性质:每一个训练数据实例都被一条唯一的路径覆盖。
决策树的学习算法是做一个递归选择最优特征的过程,用最优特征对训练数据集进行分割,对分割后的两个子数据集,选择各自子数据集的最优特征继续进行分割,如果某个子数据集已经能够正确分类,则将该节点改为叶节点。否则一直递归寻找最优特征知道没有合适特征为止。决策树可能对训练数据有很好的分类能力,对测试数据却未必,这时可能是由于过度拟合训练数据,而降低了其泛化性,可以通过剪枝操作合并过分细分的叶子节点,将数据归并到父节点来增加其泛化性。所以可以看到决策树生成过程对应着局部最优的特征选择,而剪枝对应着对模型进行全局调优。
对决策树模型有了初步认识之后,接下来将介绍决策树的建模与剪枝过程,这里重点介绍 ID3 与 C4.5 ,这两种形式的决策树学习均包括三个步骤:1)特征选择;2)决策树的生成;3)减枝。接下来的段落围绕这三部分展开。
特征选择
特征选择在于选取具有分类能力的特征,来提高决策树的学习效率,通常选择特征的标准为信息增益(ID3)与信息增益比(C4.5)。首先在这里引入一个熵(Entrop)的概念。
熵是表示随机变量不确定性的度量,对于离散随机变量 $X$ ,其概率分布为:
[P(X = x_i) = p_i , i = 1,2,…,n]
根据熵的定义,得到随机变量 $X$ 的熵为:
[H(X) = – sum_i p_i log p_i]
这里约定若 $p_i = 0$ , 则有 $ p_i log p_i = 0 $,而且这里的 $log$ 通常以 $2$ 或者 $e$ 为底(本文默认以 $2$ 为底了 )。熵越大,随机变量的不确定性就越大,下边给一个示例,对于 $ X sim Bernoulli(p) $,则下图为 $H(X) = -plogp-(1-p)log(1-p)$ 随 $p$ 变化的图:
当 $p =0$ 或者 $p=1$ 时,$H(X) = 0$,随机变量完全没有不确定性,当 $p=0.5$ 时,熵达到最大,即不确定性达到最大。有了熵的定义,下面是继而给出条件熵 $H(Y|X)$ 的定义,条件熵指的是在已知随机变量 $X$ 条件下随机变量 $Y$ 的不确定性,假设现在有 $P(X=x_i) = p_i$ ,则给定 $X$ 条件下 $Y$ 的条件熵定义如下:
[H(Y|X) = sum_i p_i H(Y|X=x_i)]
有了以上两个概念,接下来便可以定义信息增益(Information Gain)了,信息增益表示的是得知特征 $X$ 的取值情况下使得 $Y$ 的不确定性的减少程度。 现在回忆决策树,是要在给定的特征集合中选择对分类最有益的特征,如果用熵来衡量训练的混乱程度,则选择一个特征将训练集分为几个子集后,子集的混乱程度越小越好,混乱程度小正好对应了信息增益大,所以以 IG 作为特征选择是十分自然的,IG 的定义如下:
特征 $A$ 对于给定训练集合 $D$ 的信息增益 $IG(D,A)$ 为集合 $D$ 的熵与给定特征 $A$ 的条件下系统 $D$ 的条件熵 $H(D|A)$ 之差:
[IG(D,A) = H(D) –H(D|A)]
信息增益大的特征往往具有更强的分类能力, ID3 算法采用信息增益作为 特征选择的标准,对于训练数据集 $D$ ,$|D|$ 表示训练样本总数,数据共有 $K$ 个类别, 类别 $k$ 的样本集合分别用 $C_k$ 表示 ,明显有 $sum_k |C_k| = |D|$ ,假设特征 $A$ 有 $n$ 个不同取值 分别为 $left { a_1,a_2,...,a_n ight }$ ,特征 $A$ 可以将 $D$ 划分为 $n$ 个子集 $D_1,D_2,…,D_n$, $|D_i|$ 为 $D_i$ 的样本个数, 且有 $sum_i|D_i| = |D|$ ,子集 $D_i$ 属于类别 $C_k$ 的样本集合为 $C_{ik}$ ,$C_{ik}$ 即为子集 $D_i$ 中属于类别 $C_k$ 的 样本集合:$C_{ik} = D_i wedge C_k $ 。用 $|C_{ik}|$ 表示 $C_{ik}$ 集合样本的个数,接下来可以把 ID3 中信息增益算法归纳如下:
输入: 训练数据集 $D$ 与 特征 $A$
输出: 特征 $A$ 对训练数据集 $D$ 的信息增益 $IG(D,A)$.
1)计算训练集合 $D$ 的熵 $H(D)$:
[H(D) = -sum_k frac{|C_k|}{|D|}logfrac{|C_k|}{|D|}]
2)特征 $A$ 把 $D$ 划分为 $i$ 个子集,计算特征 $A$ 对数据集 $D$ 的条件熵 $H(D|A)$:
[H(D|A) = -sum_i frac{|D_i|}{|D|} sum_k frac{|C_{ik}|}{|D_i|} log frac{|C_{ik}|}{|D_i|} ]
3)计算信息增益 IG:
[IG(D,A) = H(D) – H(D|A)]
至于 C4.5 完全与 ID3 类似,只不过不是采用 $IG$ 了,而是利用信息增益比:因为用 $IG$ 作为寻找最优划分特征时,倾向于选择特征取值多的特征,所以使用信息增益比可以校正该问题,$IG_R$ 是这样定义的:
特征集 $A$ 对训练数据集合 $D$ 的信息增益比 $IG_R(D,A)$ 定义为特征 $A$ 的信息增益 $IG(D,A)$ 与训练数据集 $D$ 关于特征 $A$ 的取值熵 $H_A(D)$ 之比,即:
[IG_R (D,A) = frac {IG(D,A)}{H_A(D)}]
假设特征 $A$ 有 $n$ 个取值,则其中数据集 $D$ 关于 特征 $A$ 的熵为:
[H_A(D) = –sum_i^n frac{|D_i|}{|D|}logfrac{|D_i|}{|D|}]
由公式可见,若 $IG_R$ 不仅对特征取值多的特征有一个除以关于特征值的熵的惩罚,所以特征取值多时信息增益不一定大。 C4.5 的信息增益算法只需把 $IG(D,A)$ 换成 $IG_R(D,A)$ 即可,这里省略不写了。
决策树的生成
经过特征选择后,接下来将进入决策树的生成算法.首先看 ID3 ,算法是这样一个过程:从根节点开始,计算特征集合的信息增益,选择增益最大的特征作为节点的特征,又该特征的不同取值构建不同的子节点,对子节点递归调用特征选择过程,直到信息增益很小或没有特征可以选择为止。ID3 算法如下:
输入:训练数据 $D$ ,特征集 $A$ ,阈值 $varepsilon$ ;
输出:决策树 $T$.
1) 若 $D$ 中所有实例均为同一类别 $C_k$ ,则 $T$ 为单节点树,将 $C_k$ 作为该节点的类标记,返回 $T$;
2) 若 $A = varnothing $ ,则 $T$ 为单节点树,将 $D$ 中 类别最大的类 $C_k$ 作为该节点的类标记,返回 $T$;
3) 计算特征集合 $A$ 中各特征对 $D$ 的信息增益,选择特征集合 $A$ 中信息增益最大的特征 $A_g$;
4) 如果 $A_g$ 的信息增益小于阈值 $varepsilon$ ,则设置 $T$ 为 单节点树,将 $D$ 中 类别最大的类 $C_k$ 作为该节点的类标记,返回 $T$ ;
5) 对 $A_g$ 中的每一个取值 $a_i$ ,依 $a_i$ 将 $D$ 分割为 非空子集 $D_i$ ,以 $D_i$ 中实例最多的类作为类标记,构建子节点,由节点 $A_g$ 与子节点构成树 $T$ ,并返回 $T$;
6) 对第 $i$ 个子节点,以 $D_i$ 为训练集,$A - A_g$ 为特征集,递归调用 $1) sim 5)$ ,得到子树 $T_i$ ,返回$T_i$ .
C4.5 与 ID3 基本一致,只是在特征选择过程使用的是信息增益比,这里省略不写了。
决策树剪枝
决策树递归的生成,直到不能继续为止,这样产生的树往往对于训练数据十分准确,但不能很好的泛化到测试数据上,因为决策树考虑对训练数据尽可能的正确分类,从而构建出过度复杂的决策树,产生过拟合的现象,可以通过剪枝来降低树的复杂度,剪枝即裁剪掉树中的一些代表类别的叶节点,并将其数据合并到父节点作为新的叶节点,从而简化分类模型。剪枝是从决策树整体出发的,用来降低整个决策树的误差。通过极小化损失函数来实现。设决策树 $T$ 的叶节点的个数为 $|T|$ , $t$ 为 $T$ 的叶节点,该节点有 $N_t$ 个样本,其中类别 $k$ 的样本有 $N_{ik}$ 个,$H_t(T)$ 代表叶子节点 $t$ 的熵, 另 $a ge 0$ ,则决策树的损失函数可以定义为:
[C_a(T) = sum_t N_t H_t(T) +a|T| ag{*}]
[H_t(T) = -sum_k frac{N_{tk}}{N_t} log frac{N_{tk}}{N_t} ]
将 $(*)$ 式的第一项记做:
[C(T) = -sum _t N_t sum_k frac{N_{tk}}{N_t} log frac{N_{tk}}{N_t} = –sum_tsum_kN_{tk}log frac{N_{tk}}{N_t} ]
于是可以得到:
[C_a(T) = C(T) + a|T|]
$C(T)$ 表示决策树对于训练数据的误差,即模型与训练数据的拟合程度,$|T|$ 表示模型复杂程度,两者之间有一个权衡 $a ge 0 $,较大的 $a$ 代表选择简单的模型,反之则选择复杂的模型, $a =0$ 意味着值考虑与训练数据的拟合程度,所谓的剪枝即在 $a$ 确定的条件下选择损失最小的模型,损失函数 $C_a(T)$ 是在简单模型与复杂模型之间的一种权衡,因为 $C(T)$ 越小 $|T|$ 越大,同时使得 $C(T)$ 与 $|T|$ 减小,得到的当然是一种权衡了。而且决策树建立时,考虑的是局部的最优特征,而剪枝时损失函数会考虑的是全局损失,整体来优化模型。好比 Deep Learning 中的 fine-tune ,剪枝如下图所示:
决策树的剪枝算法:
输入:决策树 $T$ ,参数 $a$
输出:剪枝后的树 $T_a$
1) 计算每个叶节点的熵
2) 假设归并前后的对应的树分别为 $T_B$ 与 $T_A$ ,对应的损失函数的值分别为 $C _a(T_B)$ 与 $C _a(T_A)$ 如果有 $C _a(T_B) ge C _a(T_A)$ ,则进行剪枝操作,即归并到父节点。递归执行这个过程,直到$C _a(T_B) < C _a(T_A)$.
3) 返回得到的新树 $T_a $.
剪枝算法只考虑剪枝前后损失函数的差,所以剪枝可以理解为一种动态规划算法。ID3 与 C4.5 均采用这种算法即可。
对于连续属性的计算是这样的, 如果某特征有 N 个取值,那么我们有N-1种离散化的方法:<=vj的分到左子树,>vj的分到右子树。计算这N-1种情况下最大的信息增益率。
在离散属性上只需要计算1次信息增益率,而在连续属性上却需要计算N-1次,计算量是相当大的。有办法可以减少计算量。对于连续属性先进行排序,只有在决策属性发生改变的地方才需要切开。比如对Temperature进行排序: