与公众号同步更新,详细内容及相关ipynb文件在公众号中,公众号:AI入门小白
文章目录
决策树(decision tree) 是一种基本的分类与回归方法。
决策树模型呈树形结构,在分类问题中,表示基于特征对实例进行分类的过程。它可以认为是if-then 规则的集合,也可以认为是定义在特征空间与类空
间上的条件概率分布。
学习时,利用训练数据,根据损失函数最小化的原则建立决策树模型。
预测时,对新的数据,利用决策树模型进行分类。
决策树学习通常包括3个步骤:特征选择、决策树的生成和决策树的修剪。
决策树模型与学习
决策树模型
定义5.1 (决策树) 分类决策树模型是一种描述对实例进行分类的树形结构。决策树由结点(node) 和有向边(directed edge)组成。结点有两种类型: 内部结点(internal node)和叶结点(leaf node) 。内部结点表示一个特征或属性,叶结点表示一个类。
用决策树分类,从根结点开始,对实例的某一特征进行测试,根据测试结果,将实例分配到其子结点:这时,每一个子结点对应着该特征的一个取值。如此递归地对实例进行测试并分配,直至达到叶结点。最后将实例分到叶结点的类中。
图5.1 是一个决策树的示意图。图中圆和方框分别表示内部结点和叶结点。
决策树与if-then 规则
可以将决策树看成一个if-then 规则的集合。将决策树转换成if-then 规则的过程是这样的:由决策树的根结点到叶结点的每一条路径构建一条规则:路径上内部结点的特征对应着规则的条件,而叶结点的类对应着规则的结论。决策树的路径或其对应的if-then 规则集合具有一个重要的性质:互斥并且完备。这就是说,每一个实例都被一条路径或一条规则所覆盖,而且只被一条路径或一条规则所覆盖。这里所谓覆盖是指实例的特征与路径上的特征一致或实例满足规则的条件。
决策树与条件概率分布
决策树还表示给定特征条件下类的条件概率分布。这一条件概率分布定义在特征空间的一个划分(partition) 上。将特征空间划分为互不相交的单元(cell)或区域(region),并在每个单元定义一个类的概率分布就构成了一个条件概率分布。决策树的一条路径对应于划分中的一个单元。决策树所表示的条件概率分布由各个单元给定条件下类的条件概率分布组成。假设
X
X
X为表示特征的随机变量,
Y
Y
Y为表示类的随机变量,那么这个条件概率分布可以表示为
P
(
Y
∣
X
)
P(Y|X)
P(Y∣X)。
X
X
X取值于给定划分下单元的集合,
Y
Y
Y取值于类的集合。各叶结点(单元)上的条件概率往往偏向某一个类,即属于某一类的概率较大。决策树分类时将该结点的实例强行分到条件概率大的那一类去。
注:在特征的条件下所属类的概率,即决策树上对应于判断了各特征(路径)后,概率最大的叶子节点。
图5.2(a) 示意地表示了特征空间的一个划分。图中的大正方形表示特征空间。这个大正方形被若干个小矩形分割,每个小矩形表示一个单元。特征空间划分上的单元构成了一个集合,
X
X
X取值为单元的集合。为简单起见,假设只有两类:正类和负类,即
Y
Y
Y取值为+1 和 -1。小矩形中的数字表示单元的类。图5.2(b)示意地表示特征空间划分确定时,特征(单元)给定条件下类的条件概率分布。图5.2(b)中条件概率分布对应于图5.2 (a) 的划分。当某个单元
c
c
c的条件概率满足
P
(
Y
=
+
1
∣
X
=
c
)
>
0.5
P(Y = +1 | X = c) > 0.5
P(Y=+1∣X=c)>0.5时,则认为这个单元属于正类,即落在这个单元的实例都被视为正例。图5.2 © 为对应于图5.2 (b) 中条件概率分布的决策树。
决策树学习
假设给定训练数据集
D
=
{
(
x
1
,
y
1
)
,
(
x
2
,
y
2
)
,
⋯
,
(
x
N
,
y
N
)
}
D = \{(x_1, y_1), (x_2, y_2), \cdots, (x_N, y_N)\}
D={(x1,y1),(x2,y2),⋯,(xN,yN)}
其中,
x
i
=
(
x
i
(
1
)
,
x
i
(
2
)
,
⋯
,
x
i
(
n
)
)
T
x_i = (x_i^{(1)}, x_i^{(2)}, \cdots, x_i^{(n)})^T
xi=(xi(1),xi(2),⋯,xi(n))T为输入实例(特征向量),
n
n
n为特征个数,
y
i
∈
{
1
,
2
,
⋯
,
K
}
y_i \in \{1,2,\cdots,K\}
yi∈{1,2,⋯,K}为类标记,
i
=
1
,
2
,
⋯
,
N
,
N
i=1,2,\cdots,N,N
i=1,2,⋯,N,N为样本容量。决策树学习的目标是根据给定的训练数据集构建一个决策树模型,使它能够对实例进行正确的分类。
决策树学习本质上是从训练数据集中归纳出一组分类规则。
与训练数据集不相矛盾的决策树(即能对训练数据进行正确分类的决策树)可能有多个,也可能一个都没有。我们需要的是一个与训练数据矛盾较小的决策树,同时具有很好的泛化能力(对未知数据的预测能力)。
决策树学习是由训练数据集估计条件概率模型。基于特征空间划分的类的条件概率模型有无穷多个。我们选择的条件概率模型应该不仅对训练数据有很好的拟合,而且对未知数据有很好的预测。
决策树学习用损失函数表示这一目标。如下所述,决策树学习的损失函数通常是正则化的极大似然函数。决策树学习的策略是以损失函数为目标函数的最小化。
当损失函数确定以后,学习问题就变为在损失函数意义下选择最优决策树的问题。因为从所有可能的决策树中选取最优决策树是NP完全问题,所以现实中决策树学习算法通常采用启发式方法,近似求解这一最优化问题。这样得到的决策树是次最优(sub-optimal)的。
决策树学习的算法通常是一个递归地选择最优特征,并根据该特征对训练数据进行分割,使得对各个子数据集有一个最好的分类的过程。这一过程对应着对特征空间的划分,也对应着决策树的构建。
开始,构建根结点,将所有训练数据都放在根结点。选择一个最优特征,按照这一特征将训练数据集分割成子集,使得各个子集有一个在当前条件下最好的分类。如果这些子集己经能够被基本正确分类,那么构建叶结点,并将这些子集分到所对应的叶结点中去:如果还有子集不能被基本正确分类,那么就对这些子集选择新的最优特征,继续对其进行分割,构建相应的结点。如此递归地进行下去,直至所有训练数据子集被基本正确分类,或者没有合适的特征为止。最后每个子集都被分到叶结点上,即都有了明确的类。这就生成了一棵决策树。
以上方法生成的决策树可能对训练数据有很好的分类能力,但对未知的测试数据却未必有很好的分类能力,即可能发生过拟合现象。
我们需要对己生成的树自下而上进行剪枝,将树变得更简单,从而使它具有更好的泛化能力。
具体地,就是去掉过于细分的叶结点,使其回退到父结点,甚至更高的结点,然后将父结点或更高的结点改为新的叶结点。
如果特征数量很多,也可以在决策树学习开始的时候,对特征进行选择,只留下对训练数据有足够分类能力的特征。
决策树学习算法包含特征选择、决策树的生成与决策树的剪枝过程。
由于决策树表示一个条件概率分布,所以深浅不同的决策树对应着不同复杂度的概率模型。
- 决策树的生成对应于模型的局部选择,
- 决策树的剪枝对应于模型的全局选择。
- 决策树的生成只考虑局部最优,
- 相对地,决策树的剪枝则考虑全局最优。
特征选择
特征选择问题
特征选择在于选取对训练数据具有分类能力的特征。这样可以提高决策树学习的效率。如果利用一个特征进行分类的结果与随机分类的结果没有很大差别,则称这个特征是没有分类能力的。经验上扔掉这样的特征对决策树学习的精度影响不大。通常特征选择的准则是信息增益或信息增益比。
首先通过一个例子来说明特征选择问题。
例5.1 表5.1 是一个由15 个样本组成的贷款申请训练数据。数据包括贷款申请人的4 个特征(属性):第1 个特征是年龄,有3 个可能值:青年,中年,老年;第2 个特征是有工作,有2 个可能值:是,否;第3 个特征是有自己的房子,有2 个可能值:是,否;第4 个特征是信贷情况,有3 个可能值:非常好,好, 一般。表的最后一列是类别, 是否同意贷款,取2 个值:是,否。
希望通过所给的训练数据学习一个贷款申请的决策树,用以对未来的贷款申请进行分类,即当新的客户提出贷款申请时,根据申请人的特征利用决策树决定是否批准贷款申请。
特征选择是决定用哪个特征来划分特征空间。
图5.3 表示从表5.1 数据学习到的两个可能的决策树,分别由两个不同特征的根结点构成。图5.3(a) 所示的根结点的特征是年龄,有3 个取值,对应于不同的取值有不同的子结点。图5.3(b) 所示的根结点的特征是有工作,有2 个取值,对应于不同的取值有不同的子结点。两个决策树都可以从此延续下去。问题是:究竟选择哪个特征更好些?这就要求确定选择特征的准则。
直观上,如果一个特征具有更好的分类能力,或者说,按照这一特征将训练数据集分割成子集,使得各个子集在当前条件下有最好的分类,那么就更应该选择这个特征。信息增益(information gain) 就能够很好地表示这一直观的准则。
信息增益
为了便于说明,先给出熵与条件熵的定义。
在信息论与概率统计中,熵(entropy) 是表示随机变量不确定性的度量。设
X
X
X是一个取有限个值的离散随机变量,其概率分布为
P
(
X
=
x
i
)
=
p
i
,
i
=
1
,
2
,
⋯
,
N
P(X = x_i)=p_i, \ \ \ i=1,2,\cdots,N
P(X=xi)=pi, i=1,2,⋯,N
则随机变量
X
X
X的熵定义为
H
(
X
)
=
−
∑
i
=
1
n
p
i
log
p
i
(5.1)
H(X) = -\sum_{i=1}^{n} p_i \log p_i \ \ \ \tag{5.1}
H(X)=−i=1∑npilogpi (5.1)
在式(5.1)中,若
p
i
=
0
p_i = 0
pi=0,则定义
0
log
0
=
0
0\log 0 = 0
0log0=0。通常,式(5.1)中的对数以2为底或以
e
e
e为底(自然对数),这时熵的单位分别称作比特(bit)或纳特(nat)。由定义可知,熵只依赖于
X
X
X的分布,而与
X
X
X的取值无关,所以也可将
X
X
X的熵记作
H
(
p
)
H(p)
H(p),即
H
(
p
)
=
−
∑
i
=
1
n
p
i
log
p
i
(5.2)
H(p) = - \sum_{i=1}^n p_i \log p_i \ \ \ \tag{5.2}
H(p)=−i=1∑npilogpi (5.2)
熵越大,随机变量的不确定性就越大。从定义可验证
0
≤
H
(
p
)
≤
log
n
(5.3)
0 \leq H(p) \leq \log n \ \ \ \tag{5.3}
0≤H(p)≤logn (5.3)
当随机变量只取两个值,例如1,0时,即
X
X
X的分布为
P
(
X
=
1
)
=
p
,
P
(
X
=
0
)
=
1
−
p
,
0
≤
p
≤
1
P(X = 1) = p, \ \ \ P(X = 0) = 1 - p, \ \ \ 0 \leq p \leq 1
P(X=1)=p, P(X=0)=1−p, 0≤p≤1
熵为
H
(
p
)
=
−
p
log
2
p
−
(
1
−
p
)
log
2
(
1
−
p
)
(5.4)
H(p) = -p\log_2 p - (1 - p) \log_2 (1 - p)\ \ \ \tag{5.4}
H(p)=−plog2p−(1−p)log2(1−p) (5.4)
这时,熵
H
(
p
)
H(p)
H(p)随概率
p
p
p变化的曲线如图5.4所示(单位为比特)。
当 p = 0 p = 0 p=0或 p = 1 p = 1 p=1时 H ( p ) = 0 H(p) = 0 H(p)=0,随机变量完全没有不确定性。当 p = 0.5 p = 0.5 p=0.5时, H ( p ) = 1 H(p) = 1 H(p)=1,熵取值最大,随机变量不确定性最大。
设有随机变量
(
X
,
Y
)
(X,Y)
(X,Y),其联合概率分布为
P
(
X
=
x
i
,
Y
=
y
i
)
=
p
i
j
,
i
=
1
,
2
,
⋯
,
n
;
j
=
1
,
2
,
⋯
,
m
P(X = x_i, Y = y_i) = p_{ij},\ \ \ i=1,2,\cdots,n;\ \ \ j=1,2,\cdots,m
P(X=xi,Y=yi)=pij, i=1,2,⋯,n; j=1,2,⋯,m
条件熵
H
(
Y
∣
X
)
H(Y|X)
H(Y∣X)表示在己知随机变量
X
X
X的条件下随机变量
Y
Y
Y的不确定性。随机变量
X
X
X给定的条件下随机变量
Y
Y
Y的条件熵(conditional entropy)
H
(
Y
∣
X
)
H(Y|X)
H(Y∣X),定义为
X
X
X给定条件下
Y
Y
Y的条件概率分布的熵对
X
X
X的数学期望
H
(
Y
∣
X
)
=
∑
i
=
1
n
p
i
H
(
Y
∣
X
=
x
i
)
(5.5)
H(Y|X) = \sum_{i=1}^n p_i H(Y|X=x_i)\ \ \ \tag{5.5}
H(Y∣X)=i=1∑npiH(Y∣X=xi) (5.5)
这里,
p
i
=
P
(
X
=
x
i
)
,
i
=
1
,
2
,
⋯
,
n
p_i = P(X = x_i),\ \ i=1,2,\cdots,n
pi=P(X=xi), i=1,2,⋯,n。
当熵和条件熵中的概率由数据估计(特别是极大似然估计)得到时,所对应的熵与条件熵分别称为经验熵(empirical entropy) 和经验条件熵(empirical conditional entropy)。 此时,如果有0 概率,令 0 log 0 = 0 0\log 0 = 0 0log0=0。
信息增益(information gain) 表示得知特征 X X X的信息而使得类 Y Y Y的信息的不确定性(熵)减少的程度。
定义5.2(信息增益) 特征
A
A
A对训练数据集
D
D
D的信息增益
g
(
D
,
A
)
g(D, A)
g(D,A),定义为集合
D
D
D的经验熵
H
(
D
)
H(D)
H(D)与特征
A
A
A给定条件下
D
D
D的经验条件熵
H
(
D
∣
A
)
H(D|A)
H(D∣A)之差,即
g
(
D
,
A
)
=
H
(
D
)
−
H
(
D
∣
A
)
(5.6)
g(D, A) = H(D) - H(D|A)\ \ \ \tag{5.6}
g(D,A)=H(D)−H(D∣A) (5.6)
g
(
D
,
A
)
g(D, A)
g(D,A)等于
D
D
D原本的熵 减去 加入特征
A
A
A后
D
D
D的熵。
一般地,熵 H ( Y ) H(Y) H(Y)与条件熵 H ( Y ∣ X ) H(Y|X) H(Y∣X)之差称为互信息(mutual information)。决策树学习中的信息增益等价于训练数据集中类与特征的互信息(信息增益 ∈ \in ∈互信息)。
决策树学习应用信息增益准则选择特征。
经验熵 H ( D ) H(D) H(D)表示对数据集 D D D进行分类的不确定性。
经验条件熵 H ( D ∣ A ) H(D|A) H(D∣A)表示在特征 A A A给定的条件下对数据集 D D D进行分类的不确定性。
它们的差,即信息增益,就表示由于特征 A A A而使得对数据集 D D D的分类的不确定性减少的程度。
对于数据集 D D D而言,信息增益依赖于特征,不同的特征往往具有不同的信息增益。信息增益大的特征具有更强的分类能力。
根据信息增益准则的特征选择方法是:对训练数据集(或子集) D D D,计算其每个特征的信息增益,并比较它们的大小,选择信息增益最大的特征。
设训练数据集为
D
D
D,
∣
D
∣
|D|
∣D∣表示其样本容量,即样本个数。设有
K
K
K个类
C
k
C_k
Ck,
k
=
1
,
2
,
⋯
,
K
,
∣
C
k
∣
k=1,2,\cdots,K, |C_k|
k=1,2,⋯,K,∣Ck∣为属于类
C
k
C_k
Ck的样本个数,
∑
k
=
1
K
∣
C
k
∣
=
∣
D
∣
\sum_{k=1}^{K} |C_k| = |D|
∑k=1K∣Ck∣=∣D∣。设特征
A
A
A有
n
n
n个不同的取值
{
a
1
,
a
2
,
⋯
,
a
n
}
\{a_1, a_2,\cdots, a_n\}
{a1,a2,⋯,an},根据特征
A
A
A的取值将
D
D
D划分为
n
n
n 个子集
D
1
,
D
2
,
⋯
,
D
n
,
∣
D
i
∣
D_1,D_2,\cdots,D_n,|D_i|
D1,D2,⋯,Dn,∣Di∣为
D
i
D_i
Di的样本个数,
∑
i
=
1
n
∣
D
i
∣
=
∣
D
∣
\sum_{i=1}^{n} |D_i|=|D|
∑i=1n∣Di∣=∣D∣。记子集
D
i
D_i
Di中属于类
C
k
C_k
Ck的样本集合为
D
i
k
D_{ik}
Dik,即
D
i
k
=
D
i
∩
C
k
,
∣
D
i
k
∣
D_ik = D_i \cap C_k, |D_{ik}|
Dik=Di∩Ck,∣Dik∣为
D
i
k
D_{ik}
Dik的样本个数。于是信息增益的算法如下。
算法5.1(信息增益的算法)
输入:训练数据集
D
D
D和特征
A
A
A;
输出:特征
A
A
A对训练数据集
D
D
D的信息增益
g
(
D
,
A
)
g(D,A)
g(D,A)。
(1)计算数据集
D
D
D的经验熵
H
(
D
)
H(D)
H(D)
H
(
D
)
=
−
∑
k
=
1
K
∣
C
k
∣
∣
D
∣
log
2
∣
C
k
∣
∣
D
∣
(5.7)
H(D) = - \sum_{k=1}^{K} \frac{|C_k|}{|D|} \log_2 \frac{|C_k|}{|D|}\ \ \ \tag{5.7}
H(D)=−k=1∑K∣D∣∣Ck∣log2∣D∣∣Ck∣ (5.7)
(2)计算特征
A
A
A对数据集
D
D
D的经验条件熵
H
(
D
∣
A
)
H(D|A)
H(D∣A)
H
(
D
∣
A
)
=
∑
i
=
1
n
∣
D
i
∣
∣
D
∣
H
(
D
i
)
=
−
∑
i
=
1
n
∣
D
i
∣
∣
D
∣
∑
k
=
1
K
∣
D
i
k
∣
∣
D
i
∣
log
2
∣
D
i
k
∣
∣
D
i
∣
(
5.8
)
H(D|A) = \sum_{i=1}^n \frac{|D_i|}{|D|}H(D_i) = -\sum_{i=1}^n \frac{|D_i|}{|D|} \sum_{k=1}^K \frac{|D_{ik}|}{|D_i|}\log_2\frac{|D_{ik}|}{|D_i|}\ \ \ \ \ \ \ \ (5.8)
H(D∣A)=i=1∑n∣D∣∣Di∣H(Di)=−i=1∑n∣D∣∣Di∣k=1∑K∣Di∣∣Dik∣log2∣Di∣∣Dik∣ (5.8)
(3)计算信息增益
g
(
D
,
A
)
=
H
(
D
)
−
H
(
D
∣
A
)
(5.9)
g(D,A)=H(D)-H(D|A)\ \ \ \tag{5.9}
g(D,A)=H(D)−H(D∣A) (5.9)
例5.2 对表5.1所给的训练数据集
D
D
D,根据信息增益准则选择最优特征。
解 首先计算经验熵
H
(
D
)
H(D)
H(D)。
D
(
D
)
=
−
9
15
log
2
9
15
−
6
15
log
2
6
15
=
0.971
D(D) = -\frac{9}{15}\log_2 \frac{9}{15} - \frac{6}{15}\log_2 \frac{6}{15} = 0.971
D(D)=−159log2159−156log2156=0.971
然后计算各特征对数据集
D
D
D的信息增益。分别以
A
1
,
A
2
,
A
3
,
A
4
A_1,A_2,A_3,A_4
A1,A2,A3,A4表示年龄、有工作、有自己的房子和信贷情况4个特征,则
(1)
g
(
D
,
A
1
)
=
H
(
D
)
−
[
5
15
H
(
D
1
)
+
5
15
H
(
D
2
)
+
5
15
H
(
D
3
)
]
=
0.971
−
[
5
15
(
−
2
5
log
2
2
5
−
3
5
log
2
3
5
)
+
5
15
(
−
3
5
log
2
3
5
−
2
5
log
2
2
5
)
+
5
15
(
−
4
5
log
2
4
5
−
1
5
log
2
1
5
)
]
=
0.971
−
0.888
=
0.083
\begin{aligned} g(D,A_1) &= H(D) - \Bigg[\frac{5}{15}H(D_1) + \frac{5}{15}H(D_2) + \frac{5}{15}H(D_3)\Bigg] \\ &= 0.971 - \Bigg[\frac{5}{15}\bigg(-\frac{2}{5}\log_2\frac{2}{5} - \frac{3}{5}\log_2\frac{3}{5} \bigg) + \\ &\frac{5}{15}\bigg(-\frac{3}{5}\log_2\frac{3}{5} - \frac{2}{5}\log_2\frac{2}{5} \bigg) + \frac{5}{15}\bigg(-\frac{4}{5}\log_2\frac{4}{5} - \frac{1}{5}\log_2\frac{1}{5} \bigg) \Bigg] \\ &= 0.971 - 0.888 = 0.083 \end{aligned}
g(D,A1)=H(D)−[155H(D1)+155H(D2)+155H(D3)]=0.971−[155(−52log252−53log253)+155(−53log253−52log252)+155(−54log254−51log251)]=0.971−0.888=0.083
这里
D
1
,
D
2
,
D
3
D_1,D_2,D_3
D1,D2,D3分别是
D
D
D中
A
1
A_1
A1(年龄)取值为青年、中年和老年的样本子集。类似地,
(2)
g
(
D
,
A
2
)
=
H
(
D
)
−
[
5
15
H
(
D
1
)
+
10
15
H
(
D
2
)
]
=
0.971
−
[
5
15
×
0
+
10
15
(
−
4
10
log
2
4
10
−
6
10
log
2
6
10
)
]
=
0.324
\begin{aligned} g(D,A_2) &= H(D)- \Bigg[\frac{5}{15}H(D_1) + \frac{10}{15}H(D_2) \Bigg] \\ &= 0.971 - \Bigg[\frac{5}{15}\times 0 + \frac{10}{15}\bigg(-\frac{4}{10}\log_2\frac{4}{10} - \frac{6}{10}\log_2\frac{6}{10} \bigg) \Bigg]=0.324 \end{aligned}
g(D,A2)=H(D)−[155H(D1)+1510H(D2)]=0.971−[155×0+1510(−104log2104−106log2106)]=0.324
(3)
g
(
D
,
A
3
)
=
0.971
−
[
6
15
×
0
+
9
15
(
−
3
9
log
2
3
9
−
6
9
log
2
6
9
)
]
=
0.971
−
0.551
=
0.420
\begin{aligned} g(D,A_3) &= 0.971 - \Bigg[\frac{6}{15}\times 0 + \frac{9}{15}\bigg(-\frac{3}{9}\log_2\frac{3}{9} - \frac{6}{9}\log_2\frac{6}{9} \bigg) \Bigg] \\ &= 0.971 - 0.551 = 0.420 \end{aligned}
g(D,A3)=0.971−[156×0+159(−93log293−96log296)]=0.971−0.551=0.420
(4)
g
(
D
,
A
4
)
=
0.971
−
0.608
=
0.363
g(D,A_4)=0.971 - 0.608 = 0.363
g(D,A4)=0.971−0.608=0.363
最后,比较各特征的信息增益值。由于特征
A
3
A_3
A3(有自己的房子)的信息增益值最大,所以选择特征
A
3
A_3
A3作为最优特征。
信息增益比
以信息增益作为划分训练数据集的特征,存在偏向于选择取值较多的特征的问题。使用信息增益比(information gain ratio) 可以对这一问题进行校正。这是特征选择的另一准则。
定义5.3(信息增益比) 特征
A
A
A对训练数据集
D
D
D的信息增益比
g
R
(
D
,
A
)
g_R(D,A)
gR(D,A)定义为其信息增益
g
(
D
,
A
)
g(D,A)
g(D,A)与训练数据集
D
D
D关于特征
A
A
A的值的熵
H
A
(
D
)
H_A(D)
HA(D)之比,即
g
R
(
D
,
A
)
=
g
(
D
,
A
)
H
A
(
D
)
(5.10)
g_R(D,A) = \frac{g(D,A)}{H_A(D)}\ \ \ \tag{5.10}
gR(D,A)=HA(D)g(D,A) (5.10)
其中,
H
A
(
D
)
=
−
∑
i
=
1
n
∣
D
i
∣
∣
D
∣
log
2
∣
D
i
∣
∣
D
∣
,
n
H_A(D) = -\sum_{i=1}^n \frac{|D_i|}{|D|}\log_2 \frac{|D_i|}{|D|},n
HA(D)=−∑i=1n∣D∣∣Di∣log2∣D∣∣Di∣,n是特征
A
A
A取值的个数。
决策树的生成
ID3算法
ID3 算法的核心是在决策树各个结点上应用信息增益准则选择特征,递归地构建决策树。具体方法是:从根结点(root node) 开始,对结点计算所有可能的特征的信息增益,选择信息增益最大的特征作为结点的特征,由该特征的不同取值建立子结点:再对子结点递归地调用以上方法,构建决策树:直到所有特征的信息增益均很小或没有特征可以选择为止。最后得到一棵决策树。ID3 相当于用极大似然法进行概率模型的选择。
算法5.2(ID3算法)
输入:训练数据集
D
D
D,特征集
A
A
A阈值
ε
\varepsilon
ε
输出:决策树
T
T
T
(1)若
D
D
D中所有实例属于同一类
C
k
C_k
Ck,则
T
T
T为单结点树,并将类
C
k
C_k
Ck作为该结点的类标记,返回
T
T
T;
(2)若
A
=
∅
A = \emptyset
A=∅,则
T
T
T为单结点树,并将
D
D
D中实例数最大的类
C
k
C_k
Ck作为该结点的类标记,返回
T
T
T;
(3)否则,按算法5.1计算
A
A
A中各特征对
D
D
D的信息增益,选择信息增益最大的特征
A
g
A_g
Ag;
(4)如果
A
g
A_g
Ag的信息增益小于阈值
ε
\varepsilon
ε,则置
T
T
T为单结点树,并将
D
D
D中实例数最大的类
C
k
C_k
Ck作为该结点的类标记,返回
T
T
T;
(5)否则,对
A
g
A_g
Ag的每一可能值
a
i
a_i
ai,依
A
g
=
a
i
A_g = a_i
Ag=ai将
D
D
D分割为若干非空子集
D
i
D_i
Di,将
D
i
D_i
Di中实例数最大的类作为标记,构建子结点,由结点及其子结点构成树
T
T
T,返回
T
T
T;
(6)对第
i
i
i个子结点,以
D
i
D_i
Di为训练集,以
A
−
{
A
g
}
A-\{A_g\}
A−{Ag}为特征集,递归地调用步(1)~(5),得到子树
T
i
T_i
Ti,返回
T
i
T_i
Ti。
例5.3 对表5.1的训练数据集,利用ID3 算法建立决策树。
解 利用例5.2的结果,由于特征
A
3
A_3
A3(有自己的房子)的信息增益值最大,所以选择特征
A
3
A_3
A3作为根结点的特征。它将训练数据集
D
D
D划分为两个子集
D
1
D_1
D1(
A
3
A_3
A3取值为"是")和
D
2
D_2
D2(
A
3
A_3
A3取值为"否")。由于
D
1
D_1
D1只有同一类的样本点,所以它成为一个叶结点,结点的类标记为"是"。
对
D
2
D_2
D2则需从特征
A
1
A_1
A1(年龄),
A
2
A_2
A2(有工作)和
A
4
A_4
A4(信贷情况)中选择新的特征。计算各个特征的信息增益:
g
(
D
2
,
A
1
)
=
H
(
D
2
)
−
H
(
D
2
∣
A
1
)
=
0.918
−
0.667
=
0.251
g
(
D
2
,
A
2
)
=
H
(
D
2
)
−
H
(
D
2
∣
A
2
)
=
0.918
g
(
D
2
,
A
4
)
=
H
(
D
2
)
−
H
(
D
2
∣
A
4
)
=
0.474
\begin{aligned} g(D_2,A_1) &= H(D_2) - H(D_2|A_1) = 0.918 - 0.667 = 0.251 \\ g(D_2,A_2) &= H(D_2) - H(D_2|A_2) = 0.918 \\ g(D_2,A_4) &= H(D_2) - H(D_2|A_4) = 0.474 \end{aligned}
g(D2,A1)g(D2,A2)g(D2,A4)=H(D2)−H(D2∣A1)=0.918−0.667=0.251=H(D2)−H(D2∣A2)=0.918=H(D2)−H(D2∣A4)=0.474
选择信息增益最大的特征
A
2
A_2
A2(有工作)作为结点的特征。由于
A
2
A_2
A2有两个可能取值,从这一结点引出两个子结点: 一个对应"是" (有工作)的子结点,包含3 个样本,它们属于同一类,所以这是一个叶结点,类标记为"是":另一个是对应"否" (无工作)的子结点,包含6 个样本,它们也属于同一类,所以这也是一个叶结点,类标记为"否"。
这样生成一棵如图5.5 所示的决策树。该决策树只用了两个特征(有两个内部结点)。
ID3 算法只有树的生成,所以该算法生成的树容易产生过拟合。
C4.5 的生成算法
C4.5算法与ID3算法相似,C4.5算法对ID3 算法进行了改进。C4.5在生成的过程中,用信息增益比来选择特征。
算法5.3(C4.5的生成算法)
输入:训练数据集
D
D
D,特征集
A
A
A阈值
ε
\varepsilon
ε;
输出:决策树
T
T
T。
(1)如果
D
D
D中所有实例属于同一类
C
k
C_k
Ck,则置
T
T
T为单结点树,并将
C
k
C_k
Ck作为该结点的类,返回
T
T
T;
(2)若
A
=
∅
A = \emptyset
A=∅,则置
T
T
T为单结点树,并将
D
D
D中实例数最大的类
C
k
C_k
Ck作为该结点的类,返回
T
T
T;
(3)否则,按式(5.10)计算
A
A
A中各特征对
D
D
D的信息增益比,选择信息增益比最大的特征
A
g
A_g
Ag;
(4)如果
A
g
A_g
Ag的信息增益小于阈值
ε
\varepsilon
ε,则置
T
T
T为单结点树,并将
D
D
D中实例数最大的类
C
k
C_k
Ck作为该结点的类,返回
T
T
T;
(5)否则,对
A
g
A_g
Ag的每一可能值
a
i
a_i
ai,依
A
g
=
a
i
A_g = a_i
Ag=ai将
D
D
D分割为若干非空子集
D
i
D_i
Di,将
D
i
D_i
Di中实例数最大的类作为标记,构建子结点,由结点及其子结点构成树
T
T
T,返回
T
T
T;
(6)对第
i
i
i个子结点,以
D
i
D_i
Di为训练集,以
A
−
{
A
g
}
A-\{A_g\}
A−{Ag}为特征集,递归地调用步(1)~(5),得到子树
T
i
T_i
Ti,返回
T
i
T_i
Ti。
决策树的剪枝
决策树生成算法递归地产生决策树,直到不能继续下去为止。这样产生的树往往对训练数据的分类很准确,但对未知的测试数据的分类却没有那么准确,即出现过拟合现象。过拟合的原因在于学习时过多地考虑如何提高对训练数据的正确分类,从而构建出过于复杂的决策树。解决这个问题的办法是考虑决策树的复杂度,对己生成的决策树进行简化。
在决策树学习中将己生成的树进行简化的过程称为剪枝(pruning) 。具体地,剪枝从己生成的树上裁掉一些子树或叶结点, 并将其根结点或父结点作为新的叶结点,从而简化分类树模型。
决策树的剪枝往往通过极小化决策树整体的损失函数(loss function) 或代价函数(cost function) 来实现。设树
T
T
T的叶结点个数为
∣
T
∣
,
t
|T|,t
∣T∣,t是树
T
T
T的叶结点,该叶结点有
N
t
N_t
Nt个样本点,其中
k
k
k类的样本点有
N
t
k
N_{tk}
Ntk个,
k
=
1
,
2
,
⋯
,
K
,
H
t
(
T
)
k=1,2,\cdots,K,H_t(T)
k=1,2,⋯,K,Ht(T)为叶结点
t
t
t上的经验熵,
α
≥
0
\alpha \geq 0
α≥0为参数,则决策树学习的损失函数可以定义为
C
α
(
T
)
=
∑
t
=
1
∣
T
∣
N
t
H
t
(
T
)
+
α
∣
T
∣
(5.11)
C_\alpha (T) = \sum_{t=1}^{|T|} N_t H_t(T) + \alpha |T|\ \ \ \tag{5.11}
Cα(T)=t=1∑∣T∣NtHt(T)+α∣T∣ (5.11)
其中经验熵为
H
t
(
T
)
=
−
∑
k
N
t
k
N
t
log
N
t
k
N
t
(5.12)
H_t(T) = - \sum_k \frac{N_{tk}}{N_t} \log \frac{N_{tk}}{N_t}\ \ \ \tag{5.12}
Ht(T)=−k∑NtNtklogNtNtk (5.12)
在损失函数中,将式(5.11)右端的第一项记作
C
(
T
)
=
∑
t
=
1
∣
T
∣
N
t
H
t
(
T
)
=
−
∑
t
=
1
∣
T
∣
∑
k
=
1
K
N
t
k
log
N
t
k
N
t
(5.13)
C(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}\ \ \ \tag{5.13}
C(T)=t=1∑∣T∣NtHt(T)=−t=1∑∣T∣k=1∑KNtklogNtNtk (5.13)
这时有
C
α
(
T
)
=
C
(
T
)
+
α
∣
T
∣
(5.14)
C_\alpha(T) = C(T) + \alpha|T|\ \ \ \tag{5.14}
Cα(T)=C(T)+α∣T∣ (5.14)
式(5.14) 中,
C
(
T
)
C(T)
C(T)表示模型对训练数据的预测误差,即模型与训练数据的拟合程度,
∣
T
∣
|T|
∣T∣表示模型复杂度,参数
α
≥
0
\alpha \geq 0
α≥0控制两者之间的影响。较大的
α
\alpha
α促使选择较简单的模型(树) ,较小的
α
\alpha
α促使选择较复杂的模型(树)。
α
\alpha
α意味着只考虑模型与训练数据的拟合程度,不考虑模型的复杂度。
剪枝,就是当 α \alpha α确定时,选择损失函数最小的模型,即损失函数最小的子树。当 α \alpha α值确定时,子树越大,往往与训练数据的拟合越好,但是模型的复杂度就越高:相反,子树越小,模型的复杂度就越低,但是往往与训练数据的拟合不好。损失函数正好表示了对两者的平衡。
决策树生成只考虑了通过提高信息增益(或信息增益比)对训练数据进行更好的拟合。而决策树剪技通过优化损失函数还考虑了减小模型复杂度。决策树生成学习局部的模型,而决策树剪枝学习整体的模型。
算法5.4(树的剪枝算法)
输入:生成算法产生的整个树
T
T
T,参数
α
\alpha
α;
输出:修剪后的子树
T
α
T_{\alpha}
Tα。
(1)计算每个结点的经验熵。
(2)递归地从树的叶结点向上回缩。
设一组叶结点回缩到其父结点之前与之后的整体树分别为
T
B
T_B
TB与
T
A
T_A
TA,其对应的损失函数值分别是
C
α
(
T
B
)
C_{\alpha}(T_B)
Cα(TB)与
C
α
(
T
A
)
C_{\alpha}(T_A)
Cα(TA),如果
C
α
(
T
A
)
≤
C
α
(
T
B
)
(5.15)
C_{\alpha}(T_A) \leq C_{\alpha}(T_B)\ \ \ \tag{5.15}
Cα(TA)≤Cα(TB) (5.15)
则进行剪枝,即将父结点变为新的叶结点。
(3)返回(2),直至不能继续为止,得到损失函数最小的子树
T
α
T_{\alpha}
Tα
注意,式(5.15) 只需考虑两个树的损失函数的差,其计算可以在局部进行。
CART算法
分类与回归树(classification and regression tree, CART) 模型由Breiman 等人在1984 年提出,是应用广泛的决策树学习方法。CART 同样由特征选择、树的生成及剪枝组成,既可以用于分类也可以用于回归。以下将用于分类与回归的树统称为决策树。
CART 是在给定输入随机变量 X X X条件下输出随机变量 Y Y Y的条件概率分布的学习方法。
CART 假设决策树是二叉树,内部结点特征的取值为"是"和"否",左分支是取值为"是"的分支,右分支是取值为"否"的分支。这样的决策树等价于递归地二分每个特征,将输入空间即特征空间划分为有限个单元,并在这些单元上确定预测的概率分布,也就是在输入给定的条件下输出的条件概率分布。
CART 算法由以下两步组成:
(1))决策树生成:基于训练数据集生成决策树,生成的决策树要尽量大:
(2)决策树剪枝: 用验证数据集对己生成的树进行剪枝并选择最优子树,这时用损失函数最小作为剪技的标准。
CART生成
决策树的生成就是递归地构建二叉决策树的过程。对回归树用平方误差最小化准则,对分类树用基尼指数(Gini index) 最小化准则,进行特征选择,生成二叉树。
回归树的生成
假设
X
X
X与
Y
Y
Y分别为输入和输出变量,并且
Y
Y
Y是连续变量,给定训练数据集
D
=
{
(
x
1
,
y
1
)
,
(
x
2
,
y
2
)
,
⋯
,
(
x
N
,
y
N
)
}
D = \{(x_1, y_1), (x_2, y_2), \cdots, (x_N, y_N)\}
D={(x1,y1),(x2,y2),⋯,(xN,yN)}
考虑如何生成回归树。
一棵回归树对应着输入空间(即特征空间)的一个划分以及在划分的单元上的输出值。
假设己将输入空间划分为
M
M
M个单元
R
1
,
R
2
,
⋯
,
R
M
R_1, R_2, \cdots, R_M
R1,R2,⋯,RM,并且在每个单元
R
m
R_m
Rm上有一个固定的输出值
c
m
c_m
cm,于是回归树模型可表示为
f
(
x
)
=
∑
m
=
1
M
c
m
I
(
x
∈
R
m
)
(5.16)
f(x) = \sum_{m=1}^M c_m I(x \in R_m)\ \ \ \tag{5.16}
f(x)=m=1∑McmI(x∈Rm) (5.16)
当输入空间的划分确定时,可以用平方误差
∑
x
i
∈
R
m
(
y
i
−
f
(
x
i
)
)
2
\sum_{x_i \in R_m} (y_i - f(x_i))^2
∑xi∈Rm(yi−f(xi))2来表示回归树对于训练数据的预测误差,用平方误差最小的准则求解每个单元上的最优输出值。易知,单元
R
m
R_m
Rm上的
c
m
c_m
cm的最优值
c
^
m
\hat{c}_m
c^m是
R
m
R_m
Rm上的所有输入实例
x
i
x_i
xi对应的输出
y
i
y_i
yi的均值,即
c
^
m
=
a
v
e
(
y
i
∣
x
i
∈
R
m
)
(5.17)
\hat{c}_m = ave(y_i | x_i \in R_m)\ \ \ \tag{5.17}
c^m=ave(yi∣xi∈Rm) (5.17)
问题是怎样对输入空间进行划分。这里采用启发式的方法,选择第
j
j
j个变量
x
(
j
)
x^{(j)}
x(j)和它取的值
s
s
s,作为切分变量(splitting variable) 和切分点(splitting point) ,并定义两个区域:
R
1
(
j
,
s
)
=
{
x
∣
x
(
j
)
≤
s
}
和
R
2
(
j
,
s
)
=
{
x
∣
x
(
j
)
>
s
}
(5.18)
R_1(j,s) = \{x | x^{(j)} \leq s \}\ \ \ 和\\ \ \ \ R_2(j,s) = \{x | x^{(j)} > s \}\ \ \ \tag{5.18}
R1(j,s)={x∣x(j)≤s} 和 R2(j,s)={x∣x(j)>s} (5.18)
然后寻找最优切分变量
j
j
j和最优切分点
s
s
s。具体地,求解
min
j
,
s
[
min
c
1
∑
x
i
∈
R
1
(
j
,
s
)
(
y
i
−
c
1
)
2
+
min
c
2
∑
x
i
∈
R
2
(
j
,
s
)
(
y
i
−
c
2
)
2
]
(5.19)
\min_{j,s} \Bigg[\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 \Bigg]\ \ \ \tag{5.19}
j,smin[c1minxi∈R1(j,s)∑(yi−c1)2+c2minxi∈R2(j,s)∑(yi−c2)2] (5.19)
对固定输入变量
j
j
j可以找到最优切分点
s
s
s。
c
^
1
=
a
v
e
(
y
i
∣
x
i
∈
R
1
(
j
,
s
)
)
和
c
^
2
=
a
v
e
(
y
i
∣
x
i
∈
R
2
(
j
,
s
)
)
(5.20)
\hat{c}_1 = ave(y_i|x_i\in R_1(j,s))\ \ \ 和 \\ \ \ \ \hat{c}_2=ave(y_i | x_i \in R_2(j,s))\ \ \ \tag{5.20}
c^1=ave(yi∣xi∈R1(j,s)) 和 c^2=ave(yi∣xi∈R2(j,s)) (5.20)
遍历所有输入变量,找到最优的切分变量
j
j
j,构成一个对
(
j
,
s
)
(j,s)
(j,s)。依此将输入空间划分为两个区域。接着,对每个区域重复上述划分过程,直到满足停止条件为止。这样就生成一棵回归树。这样的回归树通常称为最小二乘回归树(least squares regressiont ree) ,现将算法叙述如下。
算法5.5(最小二乘回归树生成算法)
输入: 训练数据集
D
D
D;
输出: 回归树
f
(
x
)
f(x)
f(x)。
在训练数据集所在的输入空间中,递归地将每个区域划分为两个子区域并决定每个子区域上的输出值,构建二叉决策树:
(1)选择最优切分变量
j
j
j与切分点
s
s
s,求解
min
j
,
s
[
min
c
1
∑
x
i
∈
R
1
(
j
,
s
)
(
y
i
−
c
1
)
2
+
min
c
2
∑
x
i
∈
R
2
(
j
,
s
)
(
y
i
−
c
2
)
2
]
(5.21)
\min_{j,s} \Bigg[\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 \Bigg]\ \ \ \tag{5.21}
j,smin[c1minxi∈R1(j,s)∑(yi−c1)2+c2minxi∈R2(j,s)∑(yi−c2)2] (5.21)
遍历变量
j
j
j,对固定的切分变量
j
j
j扫描切分点
s
s
s,选择使式(5.21)达到最小值的对
(
j
,
s
)
(j,s)
(j,s)。
(2)用选定的对
(
j
,
s
)
(j,s)
(j,s)划分区域并决定相应的输出值:
R
1
(
j
,
s
)
=
{
x
∣
x
(
j
)
≤
s
}
,
R
2
(
j
,
s
)
=
{
x
∣
x
(
j
)
>
s
}
R_1(j,s) = \{x|x^{(j)}\leq s\},\ \ \ R_2(j,s)=\{x|x^{(j)}>s\}
R1(j,s)={x∣x(j)≤s}, R2(j,s)={x∣x(j)>s}
c
^
m
=
1
N
m
∑
x
i
∈
R
m
(
j
,
s
)
y
i
,
x
∈
R
m
,
m
=
1
,
2
\hat{c}_m = \frac{1}{N_m} \sum_{x_i \in R_m(j,s)}y_i,\ \ \ x\in R_m,\ \ \ m=1,2
c^m=Nm1xi∈Rm(j,s)∑yi, x∈Rm, m=1,2
(3)继续对两个子区域调用步骤(1),(2),直至满足停止条件。
(4)将输入空间划分为
M
M
M个区域
R
1
,
R
2
,
⋯
,
R
M
R_1,R_2,\cdots,R_M
R1,R2,⋯,RM,生成决策树:
f
(
x
)
=
∑
m
=
1
M
c
^
m
I
(
x
∈
R
m
)
f(x)=\sum_{m=1}^{M} \hat{c}_m I(x \in R_m)
f(x)=m=1∑Mc^mI(x∈Rm)
分类树的生成
分类树用基尼指数选择最优特征,同时决定该特征的最优二值切分点。
定义5.4(基尼系数) 分类问题中,假设有
K
K
K个类,样本点属于第
k
k
k类的概率为
p
k
p_k
pk,则概率分布的基尼指数定义为
G
i
n
i
(
p
)
=
∑
k
=
1
K
p
k
(
1
−
p
k
)
=
1
−
∑
k
=
1
K
p
k
2
(5.22)
Gini(p)=\sum_{k=1}^K p_k(1-p_k)=1-\sum_{k=1}^K p_k^2\ \ \ \tag{5.22}
Gini(p)=k=1∑Kpk(1−pk)=1−k=1∑Kpk2 (5.22)
对于二类分类问题,若样本点属于第1个类的概率是
p
p
p,则概率分布的基尼指数为
G
i
n
i
(
p
)
=
2
p
(
1
−
p
)
(5.23)
Gini(p)=2p(1-p)\ \ \ \tag{5.23}
Gini(p)=2p(1−p) (5.23)
对于给定的样本集合
D
D
D,其基尼指数为
G
i
n
i
(
D
)
=
1
−
∑
k
=
1
K
(
∣
C
k
∣
∣
D
∣
)
2
(5.24)
Gini(D)=1-\sum_{k=1}^K \bigg(\frac{|C_k|}{|D|}\bigg)^2\ \ \ \tag{5.24}
Gini(D)=1−k=1∑K(∣D∣∣Ck∣)2 (5.24)
这里,
C
k
C_k
Ck是
D
D
D中属于第
k
k
k类的样本子集,
K
K
K是类的个数。
如果样本集合
D
D
D根据特征
A
A
A是否取某一可能值
a
a
a被分割成
D
1
D_1
D1和
D
2
D_2
D2两部分,即
D
1
=
{
(
x
,
y
)
∈
D
∣
A
(
x
)
=
a
}
,
D
2
=
D
−
D
1
D_1 = \{(x,y) \in D | A(x)=a \},\ \ \ D_2 = D-D_1
D1={(x,y)∈D∣A(x)=a}, D2=D−D1
则在特征
A
A
A的条件下,集合
D
D
D的基尼指数定义为
G
i
n
i
(
D
,
A
)
=
∣
D
1
∣
∣
D
∣
G
i
n
i
(
D
1
)
+
∣
D
2
∣
∣
D
∣
G
i
n
i
(
D
2
)
(5.25)
Gini(D,A)=\frac{|D_1|}{|D|} Gini(D_1) + \frac{|D_2|}{|D|}Gini(D_2)\ \ \ \tag{5.25}
Gini(D,A)=∣D∣∣D1∣Gini(D1)+∣D∣∣D2∣Gini(D2) (5.25)
基尼指数
G
i
n
i
(
D
)
Gini(D)
Gini(D)表示集合
D
D
D的不确定性,基尼指数
G
i
n
i
(
D
,
A
)
Gini(D,A)
Gini(D,A)表示经
A
=
a
A=a
A=a分割后集合
D
D
D的不确定性。基尼指数值越大,样本集合的不确定性也就越大,这一点与熵相似。
图5.7显示二类分类问题中基尼指数
G
i
n
i
(
p
)
Gini(p)
Gini(p)、熵(单位比特)之半
H
(
p
)
/
2
H(p)/2
H(p)/2和分类误差率的关系。横坐标表示概率
p
p
p,纵坐标表示损失。可以看出基尼指数和熵之半的曲线很接近,都可以近似地代表分类误差率。
算法5.6(CART生成算法)
输入: 训练数据集
D
D
D,停止计算的条件;
输出:CART决策树。
根据训练数据集,从根结点开始,递归地对每个结点进行以下操作,构建二叉决策树:
(1)设结点的训练数据集为 D D D,计算现有特征对该数据集的基尼指数。此时,对每一个特征 A A A,对其可能取的每个值 a a a,根据样本点对 A = a A=a A=a的测试为"是"或"否"将 D D D分割成 D 1 D_1 D1和 D 2 D_2 D2两部分,利用式(5.25)计算 A = a A=a A=a时的基尼指数。
(2)在所有可能的特征 A A A以及它们所有可能的切分点 a a a中,选择基尼指数最小的特征及其对应的切分点作为最优特征与最优切分点。依最优特征与最优切分点,从现结点生成两个子结点,将训练数据集依特征分配到两个子结点中去。
(3)对两个子结点递归地调用(1),(2),直至满足停止条件。
(4) 生成CART决策树。
算法停止计算的条件是结点中的样本个数小于预定阈值,或样本集的基尼指数小于预定阈值(样本基本属于同一类) ,或者没有更多特征。
例5.4 根据表5.1所给训练数据集,应用CART算法生成决策树。
解 首先计算各特征的基尼指数,选择最优特征以及其最优切分点。仍采用例5.2的记号,分别以
A
1
,
A
2
,
A
3
,
A
4
A_1,A_2,A_3,A_4
A1,A2,A3,A4表示年龄、有工作、有自己的房子和信贷情况4个特征,并以1,2,3表示年龄的值为青年、中年和老年,以1,2表示有工作和有自己的房子的值为是和否,以1,2,3表示信贷情况的值为非常好、好和一般。
求特征
A
1
A_1
A1的基尼指数:
G
i
n
i
(
D
,
A
1
=
1
)
=
5
15
(
2
×
2
5
×
(
1
−
2
5
)
)
+
10
15
(
2
×
7
10
×
(
1
−
7
10
)
)
=
0.44
G
i
n
i
(
D
,
A
1
=
2
)
=
0.48
G
i
n
i
(
D
,
A
1
=
3
)
=
0.44
\begin{aligned} Gini(D,A_1=1)&=\frac{5}{15}\bigg(2 \times \frac{2}{5}\times \bigg(1-\frac{2}{5}\bigg)\bigg)+\frac{10}{15}\bigg(2\times \frac{7}{10} \times \bigg(1-\frac{7}{10}\bigg)\bigg)=0.44 \\ Gini(D,A_1=2)&=0.48 \\ Gini(D,A_1=3)&=0.44 \end{aligned}
Gini(D,A1=1)Gini(D,A1=2)Gini(D,A1=3)=155(2×52×(1−52))+1510(2×107×(1−107))=0.44=0.48=0.44
由于
G
i
n
i
(
D
,
A
1
=
1
)
Gini(D,A_1=1)
Gini(D,A1=1)和
G
i
n
i
(
D
,
A
1
=
3
)
Gini(D,A_1=3)
Gini(D,A1=3)相等,且最小,所以
A
1
=
1
A_1=1
A1=1和
A
1
=
3
A_1=3
A1=3都可以选作
A
1
A_1
A1的最优切分点。
求特征
A
2
A_2
A2和
A
3
A_3
A3的基尼指数:
G
i
n
i
(
D
,
A
2
=
1
)
=
0.32
G
i
n
i
(
D
,
A
3
=
1
)
=
0.27
Gini(D,A_2=1) = 0.32 \\ Gini(D,A_3=1) = 0.27
Gini(D,A2=1)=0.32Gini(D,A3=1)=0.27
由于
A
2
A_2
A2和
A
3
A_3
A3只有一个切分点,所以它们就是最优切分点。
求特征
A
4
A_4
A4基尼指数:
G
i
n
i
(
D
,
A
4
=
1
)
=
0.36
G
i
n
i
(
D
,
A
4
=
2
)
=
0.47
G
i
n
i
(
D
,
A
4
=
3
)
=
0.32
Gini(D,A_4=1)=0.36 \\ Gini(D,A_4=2)=0.47 \\ Gini(D,A_4=3)=0.32
Gini(D,A4=1)=0.36Gini(D,A4=2)=0.47Gini(D,A4=3)=0.32
G
i
n
i
(
D
,
A
4
=
3
)
Gini(D,A_4=3)
Gini(D,A4=3)最小,所以
A
4
=
3
A_4=3
A4=3为
A
4
A_4
A4的最优切分点。
在 A 1 , A 2 , A 3 , A 4 A_1,A_2,A_3,A_4 A1,A2,A3,A4几个特征中, G i n i ( D , A 3 = 1 ) = 0.27 Gini(D,A_3=1)=0.27 Gini(D,A3=1)=0.27最小,所以选择特征 A 3 A_3 A3为最优特征, A 3 = 1 A_3=1 A3=1为其最优切分点。于是根结点生成两个子结点, 一个是叶结点。对另一个结点继续使用以上方法在 A 1 , A 2 , A 4 A_1,A_2,A_4 A1,A2,A4中选择最优特征及其最优切分点,结果是 A 2 = 1 A_2=1 A2=1。依此计算得知,所得结点都是叶结点。
CART剪枝
CART剪枝算法由两步组成: 首先从生成算法产生的决策树 T 0 T_0 T0底端开始不断剪枝,直到 T 0 T_0 T0的根结点,形成一个子树序列 { T 0 , T 1 , ⋯ , T n } \{T_0,T_1,\cdots,T_n\} {T0,T1,⋯,Tn};然后通过交叉验证法在独立的验证数据集上对子树序列进行测试,从中选择最优子树。
1.剪枝,形成一个子树序列
在剪枝过程中,计算子树的损失函数:
C
α
(
T
)
=
C
(
T
)
+
α
∣
T
∣
(5.26)
C_{\alpha}(T) = C(T) + \alpha |T|\ \ \ \tag{5.26}
Cα(T)=C(T)+α∣T∣ (5.26)
其中,
T
T
T为任意子树,
C
(
T
)
C(T)
C(T)为对训练数据的预测误差(如基尼指数),
∣
T
∣
|T|
∣T∣为子树的叶结点个数,
α
≥
0
\alpha \geq 0
α≥0为参数,
C
α
(
T
)
C_{\alpha}(T)
Cα(T)为参数是
α
\alpha
α时的子树
T
T
T的整体损失。参数
α
\alpha
α权衡训练数据的拟合程度与模型的复杂度。
对固定的 α \alpha α,一定存在使损失函数 C α ( T ) C_{\alpha}(T) Cα(T)最小的子树,将其表示为 T α 。 T α T_{\alpha}。T_{\alpha} Tα。Tα在损失函数 C α ( T ) C_{\alpha}(T) Cα(T)最小的意义下是最优的。容易验证这样的最优子树是唯一的。当 α \alpha α大的时候,最优子树 T α T_{\alpha} Tα偏小;当 α \alpha α小的时候, 最优子树 T α T_{\alpha} Tα偏大。极端情况,当 α = 0 \alpha=0 α=0时,整体树是最优的。当 α → ∞ \alpha \rightarrow \infty α→∞时,根结点组成的单结点树是最优的。
可以用递归的方法对树进行剪枝。将 α \alpha α从小增大, 0 = α 0 < α 1 < ⋯ < α n < + ∞ 0 = \alpha_0 < \alpha_1 < \cdots < \alpha_n < +\infty 0=α0<α1<⋯<αn<+∞,产生一系列的区间 [ α i , α i + 1 ) , i = 0 , 1 , ⋯ , n [\alpha_i,\alpha_{i+1}),i=0,1,\cdots,n [αi,αi+1),i=0,1,⋯,n;剪枝得到的子树序列对应着区间 α ∈ [ α i , α i + 1 ) , i = 0 , 1 , ⋯ , n \alpha \in [\alpha_i,\alpha_{i+1}),i=0,1,\cdots,n α∈[αi,αi+1),i=0,1,⋯,n的最优子树序列 { T 0 , T 1 , ⋯ , T n } \{T_0,T_1,\cdots,T_n\} {T0,T1,⋯,Tn},序列中的子树是嵌套的。
具体地,从整体树
T
0
T_0
T0开始剪枝。对
T
0
T_0
T0的任意内部结点
t
t
t,以
t
t
t为单结点树的损失函数是
C
α
(
t
)
=
C
(
t
)
+
α
(5.27)
C_{\alpha}(t) = C(t) + \alpha \ \ \ \tag{5.27}
Cα(t)=C(t)+α (5.27)
以
t
t
t为根节点的子树
T
t
T_t
Tt的损失函数是
C
α
(
T
t
)
=
C
(
T
t
)
+
α
∣
T
t
∣
(5.28)
C_{\alpha}(T_t) = C(T_t) + \alpha|T_t|\ \ \ \tag{5.28}
Cα(Tt)=C(Tt)+α∣Tt∣ (5.28)
当
α
=
0
\alpha = 0
α=0及
α
\alpha
α充分小时,有不等式
C
α
(
T
t
)
<
C
α
(
t
)
(5.29)
C_{\alpha}(T_t) < C_{\alpha}(t)\ \ \ \tag{5.29}
Cα(Tt)<Cα(t) (5.29)
当
α
\alpha
α增大时,在某一
α
\alpha
α有
C
α
(
T
t
)
=
C
α
(
t
)
(5.30)
C_{\alpha}(T_t) = C_{\alpha}(t)\ \ \ \tag{5.30}
Cα(Tt)=Cα(t) (5.30)
当
α
\alpha
α再增大时,不等式(5.29) 反向。只要
α
=
C
(
t
)
−
C
(
T
t
)
∣
T
t
∣
−
1
\alpha = \frac{C(t)-C(T_t)}{|T_t|-1}
α=∣Tt∣−1C(t)−C(Tt),
T
t
T_t
Tt与
t
t
t有相同的损失函数值,而
t
t
t的结点少,因此
t
t
t比
T
t
T_t
Tt更可取,对
T
t
T_t
Tt进行剪枝。
为此,对
T
0
T_0
T0中每一内部结点
t
t
t,计算
g
(
t
)
=
C
(
t
)
−
C
(
T
t
)
∣
T
t
∣
−
1
(5.31)
g(t) = \frac{C(t)-C(T_t)}{|T_t|-1}\ \ \ \tag{5.31}
g(t)=∣Tt∣−1C(t)−C(Tt) (5.31)
它表示剪枝后整体损失函数减少的程度。在
T
0
T_0
T0中剪去
g
(
t
)
g(t)
g(t)最小的
T
t
T_t
Tt,将得到的子树作为
T
1
T_1
T1,同时将最小的
g
(
t
)
g(t)
g(t)设为
α
1
。
T
1
\alpha_1。T_1
α1。T1为区间
[
α
1
,
α
2
)
[\alpha_1,\alpha_2)
[α1,α2)的最优子树。
如此剪枝下去,直至得到根结点。在这一过程中,不断地增加
α
\alpha
α的值, 产生新的区间。
2.在剪枝得到的子树序列
T
0
,
T
1
,
⋯
,
T
n
T_0,T_1,\cdots,T_n
T0,T1,⋯,Tn中通过交叉验证选取最优子树
T
α
T_{\alpha}
Tα
具体地,利用独立的验证数据集,测试子树序列
T
0
,
T
1
,
⋯
,
T
n
T_0,T_1,\cdots,T_n
T0,T1,⋯,Tn中各棵子树的平方误差或基尼指数。平方误差或基尼指数最小的决策树被认为是最优的决策树。在子树序列中,每棵子树
T
1
,
T
2
⋯
,
T
n
T_1,T_2\cdots,T_n
T1,T2⋯,Tn都对应于一个参数
α
1
,
α
2
,
⋯
,
α
n
。
\alpha_1,\alpha_2,\cdots,\alpha_n。
α1,α2,⋯,αn。所以,当最优子树
T
k
T_k
Tk确定时,对应的
α
k
\alpha_k
αk也确定了,即得到最优决策树
T
α
T_{\alpha}
Tα。
算法5.7(CART剪枝算法)
输入:CART算法生成的决策树
T
0
T_0
T0;
输出:最优决策树
T
α
T_\alpha
Tα。
(1)设
k
=
0
,
T
=
T
0
k=0,T=T_0
k=0,T=T0。
(2)设
α
=
+
∞
\alpha = +\infty
α=+∞。
(3)自下而上地对各内部结点
t
t
t计算
C
(
T
t
)
,
∣
T
t
∣
C(T_t),|T_t|
C(Tt),∣Tt∣以及
g
(
t
)
=
C
(
t
)
−
C
(
T
t
)
∣
T
t
∣
−
1
g(t) = \frac{C(t)-C(T_t)}{|T_t|-1}
g(t)=∣Tt∣−1C(t)−C(Tt)
α
=
m
i
n
(
α
,
g
(
t
)
)
\alpha = min(\alpha,g(t))
α=min(α,g(t))
这里,
T
t
T_t
Tt表示以
t
t
t为根结点的子树,
C
(
T
t
)
C(T_t)
C(Tt)是对训练数据的预测误差,
∣
T
t
∣
|T_t|
∣Tt∣是
T
t
T_t
Tt的叶结点个数。
(4)对
g
(
t
)
=
α
g(t)=\alpha
g(t)=α的内部结点
t
t
t进行剪枝,井对叶结点
t
t
t以多数表决法决定其类,得到树
T
T
T。
(5)设
k
=
k
+
1
,
α
k
=
α
,
T
k
=
T
k=k+1,\alpha_k = \alpha,T_k=T
k=k+1,αk=α,Tk=T。
(6)如果
T
k
T_k
Tk不是由根结点及两个叶结点构成的树,则回到步骤(2);否则令
T
k
=
T
n
T_k=T_n
Tk=Tn。
(7)采用交叉验证法在子树序列
T
0
,
T
+
1
,
⋯
,
T
n
T_0,T+1,\cdots,T_n
T0,T+1,⋯,Tn中选取最优子树
T
α
T_\alpha
Tα
代码部分
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from collections import Counter
import math
from math import log
import pprint
# 书上题目5.1
def create_data():
datasets = [['青年', '否', '否', '一般', '否'],
['青年', '否', '否', '好', '否'],
['青年', '是', '否', '好', '是'],
['青年', '是', '是', '一般', '是'],
['青年', '否', '否', '一般', '否'],
['中年', '否', '否', '一般', '否'],
['中年', '否', '否', '好', '否'],
['中年', '是', '是', '好', '是'],
['中年', '否', '是', '非常好', '是'],
['中年', '否', '是', '非常好', '是'],
['老年', '否', '是', '非常好', '是'],
['老年', '否', '是', '好', '是'],
['老年', '是', '否', '好', '是'],
['老年', '是', '否', '非常好', '是'],
['老年', '否', '否', '一般', '否'],
]
labels = [u'年龄', u'有工作', u'有自己的房子', u'信贷情况', u'类别']
# 返回数据集和每个维度的名称
return datasets, labels
datasets, labels=create_data()
train_data = pd.DataFrame(datasets, columns=labels)
train_data
# 熵
def calc_ent(datasets):
data_length = len(datasets)
label_count = {}
for i in range(data_length):
label = datasets[i][-1]
if label not in label_count:
label_count[label] = 0
label_count[label] += 1
ent = -sum([(p / data_length) * log(p / data_length, 2)
for p in label_count.values()])
return ent
# def entropy(y):
# """
# 标签序列的熵
# """
# hist = np.bincount(y)
# ps = hist / np.sum(hist)
# return -np.sum([p * np.log2(p) for p in ps if p > 0])
# 经验条件熵
def cond_ent(datasets, axis=0):
data_length = len(datasets)
feature_sets = {}
for i in range(data_length):
feature = datasets[i][axis]
if feature not in feature_sets:
feature_sets[feature] = []
feature_sets[feature].append(datasets[i])
cond_ent = sum( [(len(p) / data_length) * calc_ent(p) for p in feature_sets.values()])
return cond_ent
# 信息增益
def info_gain(ent, cond_ent):
return ent - cond_ent
def info_gain_train(datasets):
count = len(datasets[0]) - 1
ent = calc_ent(datasets)
# ent = entropy(datasets)
best_feature = []
for c in range(count):
c_info_gain = info_gain(ent, cond_ent(datasets, axis=c))
best_feature.append((c, c_info_gain))
print('特征({}) - info_gain - {:.3f}'.format(labels[c], c_info_gain))
# 比较大小
best_ = max(best_feature, key=lambda x: x[-1])
print(best_)
return '特征({})的信息增益最大,选择为根节点特征'.format(labels[best_[0]])
info_gain_train(np.array(datasets))
利用ID3算法生成决策树,例5.3
# 定义节点类 二叉树
class Node:
def __init__(self, root=True, label=None, feature_name=None, feature=None):
self.root = root
self.label = label
self.feature_name = feature_name
self.feature = feature
self.tree = {}
self.result = {
'label:':self.label,
'feature':self.feature,
'tree':self.tree
}
def __repr__(self): # 自定义类的实例化输出
return '{}'.format(self.result)
def add_node(self, val, node):
self.tree[val] = node
def predict(self, features):
if self.root is True:
return self.label
return self.tree[features[self.feature]].predict(features)
class DTree:
def __init__(self, epsilon=0.1):
self.epsilon = epsilon
self._tree = {}
# 熵
@staticmethod
def calc_ent(datasets):
data_length = len(datasets)
label_count = {}
for i in range(data_length):
label = datasets[i][-1]
if label not in label_count:
label_count[label] = 0
label_count[label] += 1
ent = -sum([(p / data_length) * log(p / data_length, 2)
for p in label_count.values()])
return ent
# 经验条件熵
def cond_ent(self, datasets, axis=0):
data_length = len(datasets)
feature_sets = {}
for i in range(data_length):
feature = datasets[i][axis]
if feature not in feature_sets:
feature_sets[feature] = []
feature_sets[feature].append(datasets[i])
cond_ent = sum([(len(p) / data_length) * self.calc_ent(p)
for p in feature_sets.values()])
return cond_ent
# 信息增益
@staticmethod
def info_gain(ent, cond_ent):
return ent - cond_ent
def info_gain_train(self, datasets):
count = len(datasets[0]) - 1
ent = self.calc_ent(datasets)
best_feature = []
for c in range(count):
c_info_gain = self.info_gain(ent, self.cond_ent(datasets, axis=c))
best_feature.append((c, c_info_gain))
# 比较大小
best_ = max(best_feature, key=lambda x: x[-1])
return best_
def train(self, train_data):
'''
input:数据集D(DataFrame格式),特征A,阈值eta
output:决策树T
'''
_, y_train, features = train_data.iloc[:, : -1], train_data.iloc[:, -1], train_data.columns[:-1]
# 1,若D中实例属于同一类Ck,则T为单结点树,并将类Ck作为结点的类标记,返回T
if len(y_train.value_counts()) == 1: # value_counts:统计y_train中有多少种不同的值
return Node(root=True, label=y_train.iloc[0])
# 2,若A为空,则T为单节点树,将D中实例树最大的类作为该节点的类标记,返回T
if len(features) == 0:
return Node(root=True, label=y_train.value_counts().sort_values(ascending=False).index[0])
# 3,计算最大信息增益 同5.1,Ag为信息增益的最大的特征
max_feature, max_info_gain = self.info_gain_train(np.array(train_data))
max_feature_name = features[max_feature]
# 4,Ag的信息增益小于阈值eta,则置T为单节点树,并将D中是实例数最大的类Ck作为该结点的类标记,返回T
if max_info_gain < self.epsilon:
return Node(root=True, label=y_train.value_counts().sort_values(ascending=False).index[0])
# 5,构建Ag子集
node_tree = Node(root=False, feature_name=max_feature_name, feature=max_feature)
feature_list = train_data[max_feature_name].value_counts().index
for f in feature_list:
sub_train_df = train_data.loc[train_data[max_feature_name] == f].drop([max_feature_name], axis=1)
# 6,递归生成树
sub_tree = self.train(sub_train_df)
node_tree.add_node(f, sub_tree)
# pprint.pprint(node_tree.tree)
return node_tree
def fit(self, train_data):
self._tree = self.train(train_data)
return self._tree
def predict(self, X_test):
return self._tree.predict(X_test)
datasets, labels = create_data()
data_df = pd.DataFrame(datasets, columns=labels)
dt = DTree()
tree = dt.fit(data_df)
tree
dt.predict(['老年', '否', '否', '一般'])
sklearn实例
# data
def create_data():
iris = load_iris()
df = pd.DataFrame(iris.data, columns=iris.feature_names)
df['label'] = iris.target
df.columns = [
'sepal length', 'sepal width', 'petal length', 'petal width', 'label'
]
data = np.array(df.iloc[:100, [0, 1, -1]])
# print(data)
return data[:, :2], data[:, -1]
X, y = create_data()
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)
from sklearn.tree import DecisionTreeClassifier
from sklearn.tree import export_graphviz
import graphviz # 需要安装 python-graphviz和 graphviz两个包!
clf = DecisionTreeClassifier()
clf.fit(X_train, y_train)
clf.score(X_test, y_test)
tree_pic = export_graphviz(clf, out_file="mytree.pdf")
with open("mytree.pdf") as f:
dot_graph = f.read()
graphviz.Source(dot_graph)
第5章决策树-习题
习题5.1
根据表5.1所给的训练数据集,利用信息增益比(C4.5算法)生成决策树。
解答:
表5.1 贷款申请样本数据表
ID | 年龄 | 有工作 | 有自己的房子 | 信贷情况 | 类别 |
---|---|---|---|---|---|
1 | 青年 | 否 | 否 | 一般 | 否 |
2 | 青年 | 否 | 否 | 好 | 否 |
3 | 青年 | 是 | 否 | 好 | 是 |
4 | 青年 | 是 | 是 | 一般 | 是 |
5 | 青年 | 否 | 否 | 一般 | 否 |
6 | 中年 | 否 | 否 | 一般 | 否 |
7 | 中年 | 否 | 否 | 好 | 否 |
8 | 中年 | 是 | 是 | 好 | 是 |
9 | 中年 | 否 | 是 | 非常好 | 是 |
10 | 中年 | 否 | 是 | 非常好 | 是 |
11 | 老年 | 否 | 是 | 非常好 | 是 |
12 | 老年 | 否 | 是 | 好 | 是 |
13 | 老年 | 是 | 否 | 好 | 是 |
14 | 老年 | 是 | 否 | 非常好 | 是 |
15 | 老年 | 否 | 否 | 一般 | 否 |
from sklearn.tree import DecisionTreeClassifier
from sklearn import preprocessing
import numpy as np
import pandas as pd
from sklearn import tree
import graphviz
features = ["年龄", "有工作", "有自己的房子", "信贷情况"]
X_train = pd.DataFrame([
["青年", "否", "否", "一般"],
["青年", "否", "否", "好"],
["青年", "是", "否", "好"],
["青年", "是", "是", "一般"],
["青年", "否", "否", "一般"],
["中年", "否", "否", "一般"],
["中年", "否", "否", "好"],
["中年", "是", "是", "好"],
["中年", "否", "是", "非常好"],
["中年", "否", "是", "非常好"],
["老年", "否", "是", "非常好"],
["老年", "否", "是", "好"],
["老年", "是", "否", "好"],
["老年", "是", "否", "非常好"],
["老年", "否", "否", "一般"]
])
y_train = pd.DataFrame(["否", "否", "是", "是", "否",
"否", "否", "是", "是", "是",
"是", "是", "是", "是", "否"])
# 数据预处理
le_x = preprocessing.LabelEncoder()
le_x.fit(np.unique(X_train))
X_train = X_train.apply(le_x.transform)
le_y = preprocessing.LabelEncoder()
le_y.fit(np.unique(y_train))
y_train = y_train.apply(le_y.transform)
# 调用sklearn.DT建立训练模型
model_tree = DecisionTreeClassifier()
model_tree.fit(X_train, y_train)
# 可视化
dot_data = tree.export_graphviz(model_tree, out_file=None,
feature_names=features,
class_names=[str(k) for k in np.unique(y_train)],
filled=True, rounded=True,
special_characters=True)
graph = graphviz.Source(dot_data)
graph
习题5.2
已知如表5.2所示的训练数据,试用平方误差损失准则生成一个二叉回归树。
表5.2 训练数据表
x i x_i xi | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|
y i y_i yi | 4.50 | 4.75 | 4.91 | 5.34 | 5.80 | 7.05 | 7.90 | 8.23 | 8.70 | 9.00 |
解答:
决策树的生成就是递归地构建二叉决策树的过程,对回归树用平方误差最小化准则,对分类树用基尼指数(Gini index)最小化准则,进行特征选择,生成二叉树。
算法5.5(最小二乘回归树生成算法)
输入:训练数据集 D D D
输出:回归树 f ( x ) f(x) f(x)
在训练数据集所在的输入空间中,递归地将每个区域划分为两个子区域并决定每个子区域上的输出值,构建二叉决策树;
(1)选择最优切分变量 j j j与切分点 s s s,求解 min j , s [ min c 1 ∑ x i ∈ R 1 ( j , s ) ( y i − c 1 ) 2 + min c 2 ∑ x i ∈ R 2 ( j , s ) ( y i − c 2 ) 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,smin⎣⎡c1minxi∈R1(j,s)∑(yi−c1)2+c2minxi∈R2(j,s)∑(yi−c2)2⎦⎤遍历变量 j j j,对固定的切分变量 j j j扫描切分点 s s s,选择使得上式达到最小值的对 ( j , s ) (j,s) (j,s)
(2)用选定的对 ( j , s ) (j,s) (j,s)划分区域并决定相应的输出值: R 1 ( j , s ) = { x ∣ x ( j ) ⩽ s } , R 2 ( j , s ) = { x ∣ x ( j ) > s } c m ^ = 1 N m ∑ x i ∈ R m ( j , s ) y i , x ∈ R m , m = 1 , 2 R_1(j,s)=\{x|x^{(j)}\leqslant s\}, R_2(j,s)=\{x|x^{(j)} > s\} \\ \hat{c_m} = \frac{1}{N_m} \sum_{x_i \in R_m(j,s)} y_i, x \in R_m, m=1,2 R1(j,s)={x∣x(j)⩽s},R2(j,s)={x∣x(j)>s}cm^=Nm1xi∈Rm(j,s)∑yi,x∈Rm,m=1,2
(3)继续对两个子区域调用步骤(1),(2),直至满足停止条件
(4)将输入空间划分为 M M M个区域 R 1 , R 2 , ⋯ , R M R_1,R_2,\cdots,R_M R1,R2,⋯,RM,生成决策树: f ( x ) = ∑ m = 1 M c m ^ I ( x ∈ R m ) f(x)=\sum_{m=1}^M \hat{c_m} I(x \in R_m) f(x)=m=1∑Mcm^I(x∈Rm)
import numpy as np
class LeastSqRTree:
def __init__(self, train_X, y, epsilon):
# 训练集特征值
self.x = train_X
# 类别
self.y = y
# 特征总数
self.feature_count = train_X.shape[1]
# 损失阈值
self.epsilon = epsilon
# 回归树
self.tree = None
def _fit(self, x, y, feature_count, epsilon):
# 选择最优切分点变量j与切分点s
(j, s, minval, c1, c2) = self._divide(x, y, feature_count)
# 初始化树
tree = {"feature": j, "value": x[s, j], "left": None, "right": None}
if minval < self.epsilon or len(y[np.where(x[:, j] <= x[s, j])]) <= 1:
tree["left"] = c1
else:
tree["left"] = self._fit(x[np.where(x[:, j] <= x[s, j])],
y[np.where(x[:, j] <= x[s, j])],
self.feature_count, self.epsilon)
if minval < self.epsilon or len(y[np.where(x[:, j] > s)]) <= 1:
tree["right"] = c2
else:
tree["right"] = self._fit(x[np.where(x[:, j] > x[s, j])],
y[np.where(x[:, j] > x[s, j])],
self.feature_count, self.epsilon)
return tree
def fit(self):
self.tree = self._fit(self.x, self.y, self.feature_count, self.epsilon)
@staticmethod
def _divide(x, y, feature_count):
# 初始化损失误差
cost = np.zeros((feature_count, len(x)))
# 公式5.21
for i in range(feature_count):
for k in range(len(x)):
# k行i列的特征值
value = x[k, i]
y1 = y[np.where(x[:, i] <= value)]
c1 = np.mean(y1)
y2 = y[np.where(x[:, i] > value)]
c2 = np.mean(y2)
y1[:] = y1[:] - c1
y2[:] = y2[:] - c2
cost[i, k] = np.sum(y1 * y1) + np.sum(y2 * y2)
# 选取最优损失误差点
cost_index = np.where(cost == np.min(cost))
# 选取第几个特征值
j = cost_index[0][0]
# 选取特征值的切分点
s = cost_index[1][0]
# 求两个区域的均值c1,c2
c1 = np.mean(y[np.where(x[:, j] <= x[s, j])])
c2 = np.mean(y[np.where(x[:, j] > x[s, j])])
return j, s, cost[cost_index], c1, c2
train_X = np.array([[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]).T
y = np.array([4.50, 4.75, 4.91, 5.34, 5.80, 7.05, 7.90, 8.23, 8.70, 9.00])
model_tree = LeastSqRTree(train_X, y, .2)
model_tree.fit()
model_tree.tree
根据上面程序的输出,可得到用平方误差损失准则生成一个二叉回归树:
f
(
x
)
=
{
4.72
x
≤
3
5.57
3
<
x
≤
5
7.05
5
<
x
≤
6
7.9
6
<
x
≤
7
8.23
7
<
x
≤
8
8.85
x
>
8
f(x)=\begin{cases} 4.72 & x \le 3\\ 5.57 & 3 < x \le 5\\ 7.05 & 5 < x \le 6\\ 7.9 & 6 < x \le 7 \\ 8.23 & 7 < x \le 8\\ 8.85 & x > 8\\ \end{cases}
f(x)=⎩⎪⎪⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎪⎪⎧4.725.577.057.98.238.85x≤33<x≤55<x≤66<x≤77<x≤8x>8
习题5.3
证明 CART 剪枝算法中,当 α \alpha α确定时,存在唯一的最小子树 T α T_{\alpha} Tα使损失函数 C α ( T ) C_{\alpha}(T) Cα(T)最小。
解答:
**第1步:**内部节点是否剪枝只与以该节点为根节点的子树有关。
剪枝过程:
计算子树的损失函数:
C
α
(
T
)
=
C
(
T
)
+
α
C_{\alpha}(T)=C(T)+\alpha
Cα(T)=C(T)+α其中,
C
(
T
)
=
∑
t
=
1
∣
T
∣
N
t
(
1
−
∑
k
=
1
K
(
N
t
k
N
t
)
2
)
\displaystyle C(T) = \sum_{t=1}^{|T|}N_t (1 - \sum_{k=1}^K (\frac{N_{tk}}{N_t})^2)
C(T)=t=1∑∣T∣Nt(1−k=1∑K(NtNtk)2),
∣
T
∣
|T|
∣T∣是叶结点个数,
K
K
K是类别个数。
有剪枝前子树
T
0
T_0
T0,剪枝后子树
T
1
T_1
T1,满足
C
α
(
T
1
)
⩽
C
α
(
T
0
)
C_{\alpha}(T_1) \leqslant C_{\alpha}(T_0)
Cα(T1)⩽Cα(T0)则进行剪枝。
**第2步(反证法):**假设当
α
\alpha
α确定时,存在两颗子树
T
1
,
T
2
T_1,T_2
T1,T2都使得损失函数
C
α
C_{\alpha}
Cα最小。
第1种情况:假设被剪枝的子树在同一边,易知其中一个子树会由另一个子树剪枝而得到,故不可能存在两个最优子树,原结论得证。
第2种情况:假设被剪枝的子树不在同一边,易知被剪枝掉的子树都可以使损失函数
C
α
C_{\alpha}
Cα最小,故两颗子树都可以继续剪枝,故不可能存在两个最优子树,原结论得证。
习题5.4
证明 CART 剪枝算法中求出的子树序列 { T 0 , T 1 , ⋯ , T n } \{T_0,T_1,\cdots,T_n\} {T0,T1,⋯,Tn}分别是区间 α ∈ [ α i , α i + 1 ) \alpha \in [\alpha_i,\alpha_{i+1}) α∈[αi,αi+1)的最优子树 T α T_{\alpha} Tα,这里 i = 0 , 1 , ⋯ , n , 0 = α 0 < α 1 < ⋯ , α n < + ∞ i=0,1,\cdots,n,0=\alpha_0 < \alpha_1 < \cdots, \alpha_n < +\infty i=0,1,⋯,n,0=α0<α1<⋯,αn<+∞。
解答:
原结论可以表述为:将
α
\alpha
α从小增大,
0
=
α
0
<
α
1
<
⋯
<
α
n
<
+
∞
0=\alpha_0<\alpha_1<\cdots<\alpha_n < +\infty
0=α0<α1<⋯<αn<+∞,在每个区间
[
α
i
,
α
i
+
1
)
[\alpha_i,\alpha_{i+1})
[αi,αi+1)中,子树
T
i
T_i
Ti是这个区间里最优的。
**第1步:**易证,当
α
=
0
\alpha=0
α=0时,整棵树
T
0
T_0
T0是最优的,当
α
→
+
∞
\alpha \rightarrow +\infty
α→+∞时,根结点组成的单结点树(即
T
n
T_n
Tn)是最优的。
第2步:
由于每次剪枝剪的都是某个内部结点的子结点,也就是将某个内部结点的所有子结点回退到这个内部结点里,并将这个内部结点作为叶子结点。因此在计算整体的损失函数时,这个内部结点以外的值都没变,只有这个内部结点的局部损失函数改变了,因此本来需要计算全局的损失函数,但现在只需要计算内部结点剪枝前和剪枝后的损失函数。
从整体树
T
0
T_0
T0开始剪枝,对
T
0
T_0
T0的任意内部结点
t
t
t
剪枝前的状态:有
∣
T
t
∣
|T_t|
∣Tt∣个叶子结点,预测误差是
C
(
T
t
)
C(T_t)
C(Tt)
剪枝后的状态:只有本身一个叶子结点,预测误差是
C
(
t
)
C(t)
C(t)
因此剪枝前的以
t
t
t结点为根结点的子树的损失函数是
C
α
(
T
t
)
=
C
(
T
t
)
+
α
∣
T
t
∣
C_{\alpha}(T_t) = C(T_t) + \alpha|T_t|
Cα(Tt)=C(Tt)+α∣Tt∣剪枝后的损失函数是
C
α
(
t
)
=
C
(
t
)
+
α
C_{\alpha}(t) = C(t) + \alpha
Cα(t)=C(t)+α易得,一定存在一个
α
\alpha
α使得
C
α
(
T
t
)
=
C
α
(
t
)
C_{\alpha}(T_t) = C_{\alpha}(t)
Cα(Tt)=Cα(t),这个值为
α
=
C
(
t
)
−
C
(
T
t
)
∣
T
t
∣
−
1
\alpha=\frac{C(t)-C(T_t)}{|T_t|-1}
α=∣Tt∣−1C(t)−C(Tt)可知,找到
α
\alpha
α即找到了子结点
t
t
t,即完成了剪枝,得到最优子树
T
1
T_1
T1
根据书中第73页,采用以下公式计算剪枝后整体损失函数减少的程度:
g
(
t
)
=
C
(
t
)
−
C
(
T
t
)
∣
T
t
∣
−
1
g(t)=\frac{C(t)-C(T_t)}{|T_t|-1}
g(t)=∣Tt∣−1C(t)−C(Tt)在
T
0
T_0
T0中剪去
g
(
t
)
g(t)
g(t)最小的
T
t
T_t
Tt,将得到的子树作为
T
1
T_1
T1,同时将最小的
g
(
t
)
g(t)
g(t)设为
α
1
\alpha_1
α1,
T
1
T_1
T1为区间
[
α
1
,
α
2
)
[\alpha_1,\alpha_2)
[α1,α2)的最优子树。
依次类推,子树
T
i
T_i
Ti是区间
[
α
i
,
α
i
+
1
)
[\alpha_i,\alpha_{i+1})
[αi,αi+1)里最优的,原结论得证。
参考文献:
- MrTriste:https://blog.csdn.net/wjc1182511338/article/details/76793164
- http://www.pianshen.com/article/1752163397/
讨论: 为什么
α
\alpha
α要取最小的
g
(
t
)
g(t)
g(t)呢?
图5.1 最小的
g
(
t
)
g(t)
g(t)
以图中两个点为例,结点1和结点2,
g
(
t
)
2
g(t)_2
g(t)2大于
g
(
t
)
1
g(t)_1
g(t)1,假设在所有结点中
g
(
t
)
1
g(t)_1
g(t)1最小,
g
(
t
)
2
g(t)_2
g(t)2最大,两种选择方法:当选择最大值
g
(
t
)
2
g(t)_2
g(t)2,即结点2进行剪枝,但此时结点1的剪枝前的误差大于剪枝后的误差,即如果不剪枝,误差变大,依次类推,对其它所有的结点的
g
(
t
)
g(t)
g(t)都是如此,从而造成整体的累计误差更大。反之,如果选择最小值
g
(
t
)
1
g(t)_1
g(t)1,即结点1进行剪枝,则其余结点不剪的误差要小于剪枝后的误差,不剪枝为好,且整体的误差最小。从而以最小
g
(
t
)
g(t)
g(t)剪枝获得的子树是该
α
\alpha
α值下的最优子树。
数据来源:统计学习方法(第二版) &
https://github.com/fengdu78/lihang-code