分类决策树模型是一种描述对实例进行分类的树形结构。决策树由结点(node)和有向边(directed edge)组成。结点有两种类型:内部结点和叶结点。内部结点表示一个特征或属性,叶结点表示一个类。
用决策树分类,从根结点开始,对实例的某一特征进行测试,根据测试结果,将实例分配到其子结点,这时,每一个子结点对应该特征的一个取值。如此递归地对实例进行测试并分配,直至到达叶结点。最后将实例分到叶结点的类中。
可以将决策树看成一个 if-then 规则的集合。将决策树转换成 if-then 规则的过程如下:由决策树的根结点到叶结点的每一条路径构建一条规则;路径上的内部结点的特征对应规则的条件,而叶结点的类对应规则的结论。
决策树的路径或其对应的 if-then 规则集合具有一个重要性质:互斥且完备。这就是说,每一个实例都被一条路径或一条规则所覆盖,而且只被一条路径或一条规则所覆盖。
下面的例子中,决策树通过 if-then-else 的决策规则来学习数据从而估测一个正弦图像。决策树越深入,决策规则就越复杂且对数据的拟合越好,但也有可能过拟合,学到噪声数据。
import numpy as np
from sklearn.tree import DecisionTreeRegressor
import matplotlib.pyplot as pltrng = np.random.RandomState(1)
X = np.sort(5 * rng.rand(80, 1), axis=0)
y = np.sin(X).ravel()
y[::5] += 3 * (0.5 - rng.rand(16))regr_1 = DecisionTreeRegressor(max_depth=2)
regr_2 = DecisionTreeRegressor(max_depth=5)
regr_1.fit(X, y)
regr_2.fit(X, y)X_test = np.arange(0.0, 5.0, 0.01)[:, np.newaxis]
y_1 = regr_1.predict(X_test)
y_2 = regr_2.predict(X_test)plt.figure()
plt.scatter(X, y, s=20, edgecolors="black", c="darkorange", label="data")
plt.plot(X_test, y_1, color="cornflowerblue", label="max_depth=2", linewidth=2)
plt.plot(X_test, y_2, color="yellowgreen", label="max_depth=5", linewidth=2)
plt.xlabel("data")
plt.ylabel("target")
plt.title("Decision Tree Regression")
plt.legend()
plt.show()
假定给定训练数据集
D={(x1,y1),(x2,y2),⋯,(xN,yN)}D=\{(x_1,y_1),(x_2,y_2),\cdots,(x_N,y_N)\} D={(x1,y1),(x2,y2),⋯,(xN,yN)}
其中,xi=(xi(1),xi(2),⋯,xi(n))x_i=(x_i^{(1)}, x_i^{(2)},\cdots,x_i^{(n)})xi=(xi(1),xi(2),⋯,xi(n)) 为输入实例的特征向量,nnn 为特征个数,yi∈{1,2,⋯,K}y_i \in \{1, 2, \cdots, K\}yi∈{1,2,⋯,K} 为类标记。
决策树学习本质上是从训练数据集中归纳出一组分类规则。从另一个角度看,决策树学习是由训练数据集估计条件概率模型。我们选择的决策树模型不仅对训练数据有很好的拟合,而且对未知数据有很好的预测。决策树学习用损失函数表示这一目标,损失函数通常是正则化的极大似然函数。
决策树学习的算法通常是一个递归地选择最优特征,并根据该特征对训练数据进行分割,使得对各个子数据集有一个最好的分类的过程。这一过程对应特征空间的划分,也对应决策树的构建。
首先构建根结点,将所有训练数据都放在根结点。选择一个最优特征,按照这一特征将训练数据集分割成子集,使得各个子集有一个在当前条件下最好的分类。如果这些子集已经能够被基本正确分类,那么构建叶结点,并将这些子集分到所对应的叶结点中去;
如果还有子集不能够被基本正确分类,那么就对这些子集选择新的最优特征,继续对其进行分割,构建相应的结点。如此递归地进行下去,直至所有训练数据子集被基本正确分类,或者没有合适的特征为止。最后每个子集都被分到叶结点上,即都有了明确的类。
以上生成的决策树可能对训练数据有很好的分类能力,但对未知的测试数据未必有很好的分类能力,即有可能发生过拟合现象。我们需要对已生成的树自下而上进行剪枝,将树变得更简单。具体来说,就是去掉过于细分的叶结点,使其回退到父结点,甚至更高的结点,然后将父结点或更高的结点改为新的叶结点。
如果特征数量很多,也可以在决策树学习开始的时候对特征进行选择,只留下对训练数据有足够分类能力的特征。
特征选择在于选取对训练数据具有分类能力的特征,通常特征选择的准则是信息增益或信息增益比。为了便于说明,先给出熵与条件熵的定义。
熵(entropy)是表示随机变量不确定性的度量。设 XXX 是一个取有限个值的离散随机变量,其概率分布为
P(X=xi)=pi,i=1,2,⋯,nP(X=x_i)=p_i,\quad i=1,2,\cdots,n P(X=xi)=pi,i=1,2,⋯,n则随机变量 XXX 的熵定义为
H(X)=−∑i=1npilogpiH(X)=-\sum_{i=1}^n p_i \log p_i H(X)=−i=1∑npilogpi由定义可知,熵只依赖于 XXX 的分布,而与 XXX 的取值无关,所以也可以将 XXX 的熵记作 H(p)H(p)H(p). 熵越大,随机变量的不确定性就越大。从定义可验证
0≤H(p)≤logn0 \le H(p)\le \log n 0≤H(p)≤logn
设有随机变量 (X,Y)(X,Y)(X,Y),其联合概率分布为
P(X=xi,Y=yj)=pij,i=1,2,⋯,n,j=1,2,⋯,mP(X=x_i,Y=y_j)=p_{ij},\quad i=1,2,\cdots,n,\quad j=1,2,\cdots,m P(X=xi,Y=yj)=pij,i=1,2,⋯,n,j=1,2,⋯,m条件熵 H(Y∣X)H(Y|X)H(Y∣X) 表示在已知随机变量 XXX 的条件下随机变量 YYY 的不确定性:
H(Y∣X)=∑i=1npiH(Y∣X=xi),pi=P(X=xi),i=1,2,⋯,nH(Y|X)=\sum_{i=1}^n p_iH(Y|X=x_i),\quad p_i=P(X=x_i),\ i=1,2,\cdots,n H(Y∣X)=i=1∑npiH(Y∣X=xi),pi=P(X=xi), i=1,2,⋯,n当熵和条件熵中的概率由数据估计(特别是极大似然估计)得到时,所对应的熵与条件熵分别称为经验熵(empirical entropy)和经验条件熵(empirical conditional entropy)。
信息增益(information gain)表示得知特征 XXX 的信息而使得类 YYY 的信息的不确定性减少的程度。
特征 AAA 对训练数据集 DDD 的信息增益 g(D,A)g(D, A)g(D,A) 定义为集合 DDD 的经验熵与特征 AAA 给定条件下 DDD 的经验条件熵 H(D∣A)H(D|A)H(D∣A) 之差,即g(D,A)=H(D)−H(D∣A)g(D,A)=H(D)-H(D|A)g(D,A)=H(D)−H(D∣A)
决策树学习应用信息增益准则选择特征。给定训练数据集 DDD 和特征 AAA,经验熵 H(D)H(D)H(D) 表示对数据集 DDD 进行分类的不确定性,而经验条件熵 H(D∣A)H(D|A)H(D∣A) 表示在特征 AAA 给定的条件下对数据集 DDD 进行分类的不确定性。那么它们的差就表示由于特征 AAA 而使得对数据集 DDD 的分类的不确定性减少的程度。
设训练数据集为 DDD,∣D∣|D|∣D∣ 表示其样本容量,即样本个数。
设有 KKK 个类 Ck,k=1,2,⋯,KC_k,\ k=1,2,\cdots,KCk, k=1,2,⋯,K,∣Ck∣|C_k|∣Ck∣ 为属于类 CkC_kCk 的样本个数。
设特征 AAA 有 nnn 个不同的取值 {a1,a2,⋯,an}\{a_1,a_2,\cdots,a_n\}{a1,a2,⋯,an},根据特征 AAA 的取值将 DDD 划分为 nnn 个子集 D1,⋯,DnD_1,\cdots,D_nD1,⋯,Dn,∣Di∣|D_i|∣Di∣ 为 DiD_iDi 的样本个数。
记子集 DiD_iDi 中属于类 CkC_kCk 的样本的集合为 DikD_{ik}Dik,信息增益的算法如下:
输入:训练数据集 DDD 和特征 AAA。
输出:特征 AAA 对训练数据集 DDD 的信息增益 g(D,A)g(D,A)g(D,A)。
使用信息增益作为划分训练数据集的特征的依据,存在偏向于选择取值较多的特征的问题。使用信息增益比 gR(D,A)g_R(D,A)gR(D,A) 可以对这一问题进行校正。
gR(D,A)=g(D,A)HA(D)g_R(D,A)=\frac{g(D,A)}{H_A(D)} gR(D,A)=HA(D)g(D,A)其中,HA(D)=−∑i=1n∣Di∣∣D∣log2∣Di∣∣D∣H_A(D)=-\sum_{i=1}^n \frac{|D_i|}{|D|} \log_2\frac{|D_i|}{|D|}HA(D)=−∑i=1n∣D∣∣Di∣log2∣D∣∣Di∣.
ID3 算法的核心是在决策树各个结点上应用信息增益准则选择特征,递归地构建决策树。具体方法是,从根结点开始,对结点计算所有可能的特征的信息增益,选择信息增益最大的特征作为结点的特征,由该特征的不同取值建立子结点;再对子结点递归地调用以上方法,构建决策树;直到所有特征的信息增益均很小或没有特征可以选择为止。ID3 相当于用极大似然法进行概率模型的选择。
输入:训练数据集 DDD,特征集 AAA,阈值 ϵ\epsilonϵ。
输出:决策树 TTT。
以下表所示的数据集(贷款申请样本)为例,利用 ID3 算法构建决策树。
ID | 年龄 | 有工作 | 有自己的房子 | 信贷情况 | 类别 |
---|---|---|---|---|---|
1 | 青年 | 否 | 否 | 一般 | 否 |
2 | 青年 | 否 | 否 | 好 | 否 |
3 | 青年 | 是 | 否 | 好 | 是 |
4 | 青年 | 是 | 是 | 一般 | 是 |
5 | 青年 | 否 | 否 | 一般 | 否 |
6 | 中年 | 否 | 否 | 一般 | 否 |
7 | 中年 | 否 | 否 | 好 | 否 |
8 | 中年 | 是 | 是 | 好 | 是 |
9 | 中年 | 否 | 是 | 非常好 | 是 |
10 | 中年 | 否 | 是 | 非常好 | 是 |
11 | 老年 | 否 | 是 | 非常好 | 是 |
12 | 老年 | 否 | 是 | 好 | 是 |
13 | 老年 | 是 | 否 | 好 | 是 |
14 | 老年 | 是 | 否 | 非常好 | 是 |
15 | 老年 | 否 | 否 | 一般 | 否 |
首先由之前的信息增益算法计算出特征 A3A_3A3 (有自己的房子)信息增益值最大(步骤省略),所以选择特征 A3A_3A3 作为根结点的特征。它将训练集划分为两个子集 D1D_1D1(A3A_3A3 取值为“是”)和 D2D_2D2(A3A_3A3 取值为“否”)。由于 D1D_1D1 只有同一类的样本点,所以它成为一个叶结点。
对 D2D_2D2 则需要从 A1A_1A1(年龄),A2A_2A2(有工作)和 A4A_4A4(信贷情况)中选择新的特征。计算各个特征对数据集 D2D_2D2 的信息增益,得到信息增益最大的特征 A2A_2A2(有工作)。从这一结点引出两个子结点,一个对应“有工作”的子结点,包含 3 个样本,属于同一个类(“是”),成为叶结点;另一个对应“无工作”的结点,包含 6 个样本,也都属于同一类(“否”),成为叶结点。
生成的决策树如下图所示:
我们构建一个决策树来对鸢尾花数据集进行分类,经过训练,我们可以使用 export_graphviz
导出器以 Graphviz 格式导出决策树:
from sklearn.datasets import load_iris
from sklearn import tree
import graphviz
iris = load_iris()
clf = tree.DecisionTreeClassifier()
clf = clf.fit(iris.data, iris.target)dot_data = tree.export_graphviz(clf, out_file=None, feature_names=iris.feature_names,class_names=iris.target_names, filled=True,rounded=True, special_characters=True)
graph = graphviz.Source(dot_data)
graph
该决策树决策过程涉及到 CART 算法,我们稍后会详细介绍。
C4.5 算法在生成的过程中,用信息增益比来选择特征。
输入:训练数据集 DDD,特征集 AAA,阈值 ϵ\epsilonϵ。
输出:决策树 TTT。
决策树生成算法生成的树往往会出现过拟合现象,对已生成的树进行简化的过程称为剪枝(pruning)。决策树的剪枝往往通过极小化决策树整体的损失函数或代价函数来实现。设树 TTT 的叶结点个数为 ∣T∣|T|∣T∣,ttt 是树 TTT 的叶结点,该叶结点有 NtN_tNt 个样本点,其中属于 kkk 类的样本点有 NtkN_{tk}Ntk 个,Ht(T)H_t(T)Ht(T) 为叶结点 ttt 上的经验熵,则决策树学习的损失函数可以定义为
Cα(T)=∑t=1∣T∣NtHt(T)+α∣T∣C_\alpha(T)=\sum_{t=1}^{|T|}N_tH_t(T)+\alpha|T| Cα(T)=t=1∑∣T∣NtHt(T)+α∣T∣其中经验熵为Ht(T)=−∑kNtkNtlogNtkNtH_t(T)=-\sum_k \frac{N_{tk}}{N_t} \log \frac{N_{tk}}{N_t} Ht(T)=−k∑NtNtklogNtNtk令 C(T)=∑t=1∣T∣NtHt(T)=−∑t=1∣T∣∑k=1KNtklogNtkNtC(T)=\sum_{t=1}^{|T|}N_tH_t(T)=-\sum_{t=1}^{|T|}\sum_{k=1}^K N_{tk} \log \frac{N_{tk}}{N_t} C(T)=t=1∑∣T∣NtHt(T)=−t=1∑∣T∣k=1∑KNtklogNtNtk 则损失函数为 Cα(T)=C(T)+α∣T∣C_\alpha(T)=C(T)+\alpha|T|Cα(T)=C(T)+α∣T∣
C(T)C(T)C(T) 表示模型对训练数据的预测误差,即模型与训练数据的拟合程度,∣T∣|T|∣T∣ 表示模型复杂度,参数 α≥0\alpha \ge 0α≥0 控制两者之间的影响。较大的 α\alphaα 促使选择较简单的模型,较小的 α\alphaα 促使选择较复杂的模型。
决策树生成只考虑了通过提高信息增益对训练数据进行更好的拟合,而决策树剪枝通过优化损失函数还考虑了减小模型复杂度。决策树生成学习局部的模型,而决策树剪枝学习整体的模型。
下面介绍一种简单的决策树学习的剪枝算法:
输入:生成算法产生的整个树 TTT,参数α\alphaα。
输出:修剪后的子树 TαT_\alphaTα。
计算每个结点的经验熵;
递归地从树的叶结点向上回缩;
设一组叶结点回缩到其父结点之前与之后的整体树分别为 TBT_BTB 与 TAT_ATA,其对应的损失函数值分别是 Cα(TB)C_\alpha(T_B)Cα(TB) 与 Cα(TA)C_\alpha(T_A)Cα(TA),如果Cα(TB)≥Cα(TA)C_\alpha(T_B)\ge C_\alpha(T_A)Cα(TB)≥Cα(TA)则进行剪枝,即将父结点变为新的叶结点。上式只需考虑两个树的损失函数的差,其计算可以在局部进行,可由一种动态规划的算法实现。
返回步骤 2,直至不能继续为止,得到损失函数最小的子树 TαT_\alphaTα。
分类与回归树(classification and regression tree,CART)是广泛使用的决策树学习方法。CART 是在给定输入随机变量 XXX 条件下输出随机变量 YYY 的条件概率分布的学习方法。CART 算法由以下两步组成:
(1) 决策树生成:基于训练数据集生成决策树,生成的决策树要尽量大。
(2) 决策树剪枝:用验证数据集对已生成的树进行剪枝并选择最优子树,这时用损失函数最小作为剪枝的标准。
决策树的生成就是递归地构建二叉决策树的过程。对回归树用平方误差最小化准则,对分类树用基尼指数(Gini index)最小化准则,进行特征选择,生成二叉树。
给定训练数据集 D={(x1,y1),(x2,y2),⋯,(xN,yN)}D=\{(x_1,y_1),(x_2,y_2),\cdots,(x_N,y_N)\}D={(x1,y1),(x2,y2),⋯,(xN,yN)},考虑如何生成回归树。
一颗回归树对应着输入空间的一个划分以及在划分的单元上的输出值。假设已将输入空间划分为 MMM 个单元 R1,R2,⋯,RMR_1,R_2,\cdots,R_MR1,R2,⋯,RM,并且在每个单元上有一个固定的输出值 cmc_mcm,于是回归树模型可表示为
f(x)=∑m=1McmI(x∈Rm)f(x)=\sum_{m=1}^M c_mI(x \in R_m) f(x)=m=1∑McmI(x∈Rm)
当输入空间的划分确定时,可用平方误差 ∑xi∈Rm(yi−f(xi))2\sum_{x_i\in R_m}(y_i-f(x_i))^2∑xi∈Rm(yi−f(xi))2 来表示回归树对训练数据的预测误差。单元 RmR_mRm 上的最优输出值 c^m\hat{c}_mc^m 是 RmR_mRm 上的所有输入实例 xix_ixi 对应的输出 yiy_iyi 的均值,即
c^m=avg(yi∣xi∈Rm)\hat{c}_m=\text{avg}(y_i|x_i\in R_m) c^m=avg(yi∣xi∈Rm)
问题是怎样对输入空间进行划分。这里采用启发式的方法,选择第 jjj 个变量 x(j)x^{(j)}x(j) 和它取的值 sss 作为切分变量和切分点,并定义两个区域:
R1(j,s)={x∣x(j)≤s},R2(j,s)={x∣x(j)>s}R_1(j,s)=\{x|x^{(j)}\le s\},\ \ R_2(j,s)=\{x|x^{(j)} > s\} R1(j,s)={x∣x(j)≤s}, R2(j,s)={x∣x(j)>s}
然后寻找最优切分变量 jjj 和最优切分点 sss。具体地,求解
minj,s[minc1∑xi∈R1(j,s)(yi−c1)2+minc2∑xi∈R2(j,s)(yi−c2)2]\min_{j,s}\left[\min_{c_1}\sum_{x_i \in R_1(j,s)}(y_i-c_1)^2 + \min_{c_2}\sum_{x_i \in R_2(j,s)}(y_i-c_2)^2\right] j,sminc1minxi∈R1(j,s)∑(yi−c1)2+c2minxi∈R2(j,s)∑(yi−c2)2
对固定输入变量 jjj,可以找到最优切分点 sss,遍历所有输入变量,找到最优的切分变量 jjj,构成一个对 (j,s)(j,s)(j,s)。依次将输入空间划分为两个区域。接着,对每个区域重复上述划分过程,直到满足停止条件为止。这样的回归树通常称为最小二乘回归树。
分类树用基尼指数选择最优特征,同时决定该特征的最优二值切分点。
分类问题中,假设有 KKK 个类,样本点属于第 kkk 类的概率为 pkp_kpk,则概率分布的基尼指数定义为
Gini(p)=∑k=1Kpk(1−pk)=1−∑k=1Kpk2\text{Gini}(p)=\sum_{k=1}^Kp_k(1-p_k)=1-\sum_{k=1}^K p_k^2 Gini(p)=k=1∑Kpk(1−pk)=1−k=1∑Kpk2
对于给定的样本集合 DDD,其基尼指数为
Gini(D)=1−∑k=1K(∣Ck∣∣D∣)2\text{Gini}(D)=1-\sum_{k=1}^K\left(\frac{|C_k|}{|D|}\right)^2 Gini(D)=1−k=1∑K(∣D∣∣Ck∣)2 其中,CkC_kCk 是 DDD 中属于第 kkk 类的样本子集。
如果样本集合 DDD 根据特征 AAA 是否取某一可能值 aaa 被分割成 D1D_1D1 和 D1D_1D1 两部分,则在特征 AAA 的条件下,集合 DDD 的基尼指数定义为
Gini(D,A)=∣D1∣∣D∣Gini(D1)+∣D2∣∣D∣Gini(D2)\text{Gini}(D,A)=\frac{|D_1|}{|D|}\text{Gini}(D_1)+\frac{|D_2|}{|D|}\text{Gini}(D_2) Gini(D,A)=∣D∣∣D1∣Gini(D1)+∣D∣∣D2∣Gini(D2)
基尼指数 Gini(D)\text{Gini}(D)Gini(D) 表示集合 DDD 的不确定性,基尼指数越大,样本集合的不确定性也就越大,这一点与熵相似。
分类树生成算法:
输入:训练数据集 DDD,停止计算的条件
输出:CART 决策树
根据训练数据集,从根结点开始,递归地对每个结点进行以下操作,构建二叉决策树:
算法停止计算的条件是结点中的样本个数小于预定阈值或样本集的基尼指数小于预定阈值,或者没有更多特征。
CART 剪枝算法由两步组成:首先从生成算法产生的决策树 T0T_0T0 底端开始不断剪枝,直到 T0T_0T0 的根结点,形成一个子树序列 {T0,T1,⋯,Tn}\{T_0,T_1,\cdots, T_n\}{T0,T1,⋯,Tn};然后通过交叉验证法在独立的验证数据集上对子树序列进行测试,从中选择最优子树。
剪枝,形成一个子树序列
在剪枝过程中,计算子树的损失函数 Cα(T)=C(T)+α∣T∣C_\alpha(T)=C(T)+\alpha|T|Cα(T)=C(T)+α∣T∣ 对于固定的 α\alphaα,一定存在使损失函数 Cα(T)C_\alpha(T)Cα(T) 最小的子树 TαT_\alphaTα。Breiman 等人证明:可以用递归的方法对树进行剪枝:
将 α\alphaα 从小增大,0=α0<α1<...<αn<+∞0=\alpha_0<\alpha_1<...<\alpha_n<+\infty0=α0<α1<...<αn<+∞,产生一系列区间 [αi,αi+1)[\alpha_i,\alpha_{i+1})[αi,αi+1),剪枝得到的子树序列对应着区间 α∈[αi,αi+1),i=0,1,...,n\alpha \in [\alpha_i,\alpha_{i+1}), i=0,1,...,nα∈[αi,αi+1),i=0,1,...,n 的最优子树序列 {T0,T1,⋯,Tn}\{T_0,T_1,\cdots, T_n\}{T0,T1,⋯,Tn},序列中的子树是嵌套的。
具体地,从整体树 T0T_0T0 开始剪枝,对 T0T_0T0 的任意内部结点 ttt,以 ttt 为单结点树的损失函数是Cα(t)=C(t)+αC_\alpha(t)=C(t)+\alphaCα(t)=C(t)+α 以 ttt 为根结点的子树 TtT_tTt 的损失函数是 Cα(Tt)=C(Tt)+α∣Tt∣C_\alpha(T_t)=C(T_t)+\alpha|T_t|Cα(Tt)=C(Tt)+α∣Tt∣ 当 α=0\alpha=0α=0 及 α\alphaα 充分小时,有不等式 Cα(Tt)
为此,对 T0T_0T0 中每一内部结点 ttt,自下而上计算 g(t)=C(t)−C(Tt)∣Tt∣−1g(t)=\frac{C(t)-C(T_t)}{|T_t|-1}g(t)=∣Tt∣−1C(t)−C(Tt) 它表示剪枝后整体损失函数减少的程度。在 T0T_0T0 中减去 g(t)g(t)g(t) 最小的 TtT_tTt,将得到的子树作为 T1T_1T1,同时将最小的 g(t)g(t)g(t) 设为 α1\alpha_1α1。T1T_1T1 为区间 [α1,α2)[\alpha_1,\alpha_2)[α1,α2) 的最优子树。
如此剪枝下去,直至得到根结点。在这一过程中,不断地增加 α\alphaα 的值,产生新的区间。
在剪枝得到的子树序列中通过交叉验证选取最优子树 TαT_\alphaTα
[1] 《机器学习方法》,李航,清华大学出版社。
[2] sklearn 中文文档,https://www.sklearncn.cn/11/。