决策树
基本介绍 {#sec:basic}
决策树是一个树结构,它既可以是二叉树,也可以是多叉树。
它的每一个非叶子节点代表对某一个属性的测试,而每一个叶子节点存放具体的类别。
它的决策从根节点开始,根据分支节点来测试属性并进入到树的下层相应的分支,直到抵达叶子节点得到类别。
决策树是基于树结构进行决策的,这符合我们对问题的决策方案,可解释性较强。
当我们判断一个人能不能偿还债务的时候,我们需要关注这个人的收入情况,这个人的家庭的财产状况(例如是否有房子可以抵押)等等。
在经过一系列的属性判断决策之后,我们会得到判断他能不能偿还债务。
优点:
模型可以直接可视化,可解释性强,既可以用于分类也可以用于回归,算法复杂度低,既可以处理离散属性,也可以处理连续性属性。
缺点:树的结果不宜过度复杂,容易过拟合。可以限制树的深度,叶子节点样本的数量等剪枝策略来缓解过拟合。
随机森林中使用多颗决策树以及随机选择属性的方式来降低过拟合的风险。
不过这个属于bagging的范畴,后面会单独出一章来讲解bagging和boosting的相关内容。
引用一个例子,来源(2)
先看一个根据房产,婚姻以及年收入来判断是否能够偿还债务的数据表格:
通过该数据,构建的决策树如下:
根据构建的决策树,对于新来的样本就可以顺着决策树的的分支来确定他是否可以偿还债务。
训练
决策树的训练过程就是树以及分支节点测试条件进行构建的过程。
我们首先从根节点开始,采用贪心算法来选择某一个属性的某一种值进行划分成几(二叉树的话为2)个部分,形成它的子分支;对于它的子分支,递归进行此划分操作。
这引出两个问题:(1) 如何划分属性,(2)如何选择属性
如何划分属性
对于一个人的收入状况,如果是用连续的值表示,那我们该如何对收入进行划分呢?如果是用离散的"高",“中等"或者"低”,该如何划分呢?具体请参见Section属性划分。
如何选择属性
回顾我们的树构建过程。它从根节点贪心的选择一个属性的最优划分,然后划分成子分支。那么对属性或者划分进行贪心选择的目的是什么呢?
让它的各个子分支尽可能的"纯",或者说使它的各个子分支的所属类别尽可能的相同。
这很容易引出一个问题,如何定义一个分支的纯度呢?具体请参见Section纯度的界定,Section贪心选择
属性划分
-
属性的取值离散,且不要求是二叉树,可以直接用属性的各个值形成不同的分支。例如一个人的收入属性有"高","中等"和"低"三种类别,那么按照收入划分的话,就可以直接划分为3个分支
-
属性的取值离散,且要求是二叉树,那就需要把属性的取值划分成两个集合,并分别测试哪种划分效果最好。例如收入属性可以尝试"高,中等"和"低"这种划分
-
属性的取值连续,且要求是二叉树,这时候需要选择连续值的某一个值point为分界点,以 > p o i n t >point >point和 < = p o i n t <=point <=point分成两部分。为了选取point,可以将全部样本的这列属性的值排序,然后不断尝试连续的两个值的中值作为分界点。
-
属性的取值连续,且不要求是二叉树,很少会有,可以采用将连续的值域范围切成几个块,然后每个块分到一个分支中。
"纯度"的界定
本节主要包括纯度的定义,以及经过某一次划分后纯度提升的""量。这个"量"有多种衡量的标准,从而有了以下三种算法:
ID3算法
对于一个数据集合,如何定义它的"纯度"呢?回忆上一章中"熵"的定义,熵衡量了传输信息所需要的最小的数据量。信息越纯,它含有的信息量越小。因此我们可以直接用熵 = = =纯度,也就是它的信息量。
令
D
D
D表示使用样本的类别,也就是样本的值对样本进行的划分,则
D
D
D的熵为
H
(
D
)
=
−
∑
i
p
i
log
p
i
H(D) = -\sum_{i} p_i \log p_i
H(D)=−i∑pilogpi
其中
p
i
p_i
pi为第
i
i
i个类别的在训练样本中出现的概率,它可以使用第
i
i
i个类别的样本数除以总的样本数来求得。
有了纯度的定义,对于给定的一个划分,我们来计算经过这次划分后它的纯度的度量。
我们假定通过属性A进行划分,那么划分后的熵为
H
A
(
D
)
=
∑
j
=
1
v
∣
D
j
∣
∣
D
∣
H
(
D
j
)
H_A(D) = \sum_{j=1}^{v} \frac{|D_j|}{|D|} H(D_j)
HA(D)=j=1∑v∣D∣∣Dj∣H(Dj)
其中
D
j
D_j
Dj表示属性A的值为
j
j
j的样本,
∣
D
j
∣
|D_j|
∣Dj∣表示的是样本数。也就是说通过属性
A
A
A对训练样本集合
D
D
D划分成了
v
v
v个分支,
H
A
(
D
)
H_A(D)
HA(D)表达的是各个分支的熵的期望平均值(各个分支的熵乘以各个分支所占的样本比例)。
利用划分前的熵
H
(
D
)
H(D)
H(D),以及划分后的
H
A
(
D
)
H_A(D)
HA(D),我们有经过这次划分后的信息增益:
G
a
i
n
(
D
,
A
)
=
H
(
D
)
−
H
A
(
D
)
Gain(D, A) = H(D) - H_A(D)
Gain(D,A)=H(D)−HA(D)
C4.5算法
ID3算法有一个明显的不足,它一般会优先选择有较多属性值得feature,即
∣
v
∣
|v|
∣v∣比较大的feature。
例如数据集合D有一列属性叫
I
D
ID
ID,它是各个样本的唯一标识,且在各个训练样本中都不相同,因此通过
I
D
ID
ID进行划分后,每个子分支都只有一个样本,且最纯,即每一个子分支的熵都为
0
0
0。这样划分之后的信息熵为达到最小值
0
0
0,也就是说
我们获得了最大的信息增益。然而,我们知道
I
D
ID
ID原本就不具有分类的意义。
C4.5算法就是为了克服这种多值属性的不足而出现的。如同我们的预期,我们可以对这样的值比较多的属性增加惩罚项,我们的惩罚项用分裂信息(split
information)来衡量,它记录的是各个子分支中样本数量的纯度。即
S
p
l
i
t
I
n
f
o
(
D
,
A
)
=
−
∑
i
=
1
v
∣
D
i
∣
∣
D
∣
log
∣
D
i
∣
∣
D
∣
SplitInfo(D, A) = -\sum_{i=1}^{v} \frac{|D_i|}{|D|} \log \frac{|D_i|}{|D|}
SplitInfo(D,A)=−i=1∑v∣D∣∣Di∣log∣D∣∣Di∣
根据熵的概念,我们可以知道
v
v
v越大,即值越多,SplitInfo越大;
∣
D
i
∣
|D_i|
∣Di∣之间相差越小,SplitInfo越大。从而,对于前面所说的
I
D
ID
ID分割的问题,我们很容易有惩罚项SplitInfo非常大。
有了惩罚项,很显然,它应该跑到信息增益的分母上来进行惩罚,从而我们有信息增益率
G
a
i
n
r
a
t
i
o
(
D
,
A
)
=
G
a
i
n
(
D
,
A
)
S
p
l
i
t
I
n
f
o
(
D
,
A
)
Gain_{ratio}(D, A) = \frac{Gain(D, A)}{SplitInfo(D,A)}
Gainratio(D,A)=SplitInfo(D,A)Gain(D,A)
CART算法
ID3和C4.5算法中在使用一个属性后,
这个属性就不再被使用了,这种快速切割的方式会影响算法的效果。CART是一颗二叉树,对于每一个分支节点都会有两个孩子。CART使用的表述纯度的概念的是Gini值,同样是数据越纯,Gini值越小。
G
i
n
i
(
D
)
=
1
−
∑
i
(
∣
D
i
∣
∣
D
∣
)
2
=
1
−
∑
i
p
i
2
Gini(D) = 1- \sum_{i} (\frac{|D_i|}{|D|})^2 = 1- \sum_{i} p_i^2
Gini(D)=1−i∑(∣D∣∣Di∣)2=1−i∑pi2
划分后的基尼系数为 G i n i ( D , A ) = ∑ j = 1 v ∣ D j ∣ ∣ D ∣ G i n i ( D j ) \begin{aligned} Gini(D, A) = \sum_{j=1}^{v} \frac{|D_j|}{|D|} Gini(D_j)\end{aligned} Gini(D,A)=j=1∑v∣D∣∣Dj∣Gini(Dj)
从而它的增益为 G a i n G i n i ( D , A ) = G i n i ( D ) − G i n i ( D , A ) Gain_{Gini}(D, A) = Gini(D) - Gini(D, A) GainGini(D,A)=Gini(D)−Gini(D,A)
贪心选择
针对上述的每一个算法,树在构造的时候,会遍历候选属性的每一个划分,然后选择能够最大化增益的属性以及划分。
在实际算法运行的时候,并不需要每次都计算增益,由于在进行划分之前的纯度值是固定的,采用不同的划分后的纯度值是不定的,我们最大化信息增益相当于最小化划分后的纯度值。
对应于上述的三种算法,相当于最小化
G
a
i
n
(
D
,
A
)
Gain(D,A)
Gain(D,A),
G
a
i
n
r
a
t
i
o
(
D
,
A
)
Gain_{ratio}(D,A)
Gainratio(D,A),
以及
G
a
i
n
G
i
n
i
(
D
,
A
)
Gain_{Gini}(D,A)
GainGini(D,A)。
决策树算法
我们引用一个书中的算法来解释一下决策树的构造过程。
步骤
1
1
1和
2
2
2为停止条件:
(
a
)
(a)
(a)
当前节点已经足够的纯,全部属于一个类别,
(
b
)
(b)
(b)当前属性已经全部用完,无法再进行下一步划分
步骤 3 3 3为贪心选择的过程,我们找到一个最优属性的最优划分。
步骤 4 4 4这个是额外的步骤,主要是为了给划分进行一定的限制,要求达到一定的信息增益。
步骤 5 5 5为按照属性 A g A_g Ag划分的过程,里面进行类别的话为废话,这个明显可以通过第 6 6 6步的下一轮递归搞定。
步骤 6 6 6才是递归的核心,它应该和第 5 5 5步合并。
额外注意事项
剪枝
剪枝有前剪枝和后剪枝,算法C4.5中第 4 4 4步描述的是前剪枝算法。后剪枝是当树构建完毕后,递归的从树的叶子节点向上回缩的过程,如果满足一定条件,将叶子节点与它的父节点合并一个叶子节点(应该还有很多内容,后续待补充!!)。
缺失值
有些样本有缺失值,一种方法是直接删除样本,但会损失样本信息,第二种方法是对缺失的样本补充其均值等,第三种方法是概率化样本,引用知乎的一段话:
其实缺失值问题可以从三个方面来考虑1.
在选择分裂属性的时候,训练样本存在缺失值,如何处理?假如你使用ID3算法,那么选择分类属性时,就要计算所有属性的熵增(信息增益,Gain)。假设10个样本,属性是a,b,c。在计算a属性熵时发现,第10个样本的a属性缺失,那么就把第10个样本去掉,前9个样本组成新的样本集,在新样本集上按正常方法计算a属性的熵增。然后结果乘0.9(新样本占raw样本的比例),就是a属性最终的熵。2.
分类属性选择完成,对训练样本分类,发现属性缺失怎么办?比如该节点是根据a属性划分,但是待分类样本a属性缺失,怎么办呢?假设a属性离散,有1,2两种取值,那么就把该样本分配到两个子节点中去,但是权重由1变为相应离散值个数占样本的比例。然后计算错误率的时候,注意,不是每个样本都是权重为1,存在分数。3.
训练完成,给测试集样本分类,有缺失值怎么办?这时候,就不能按比例分配了,因为你必须给该样本一个确定的label,而不是薛定谔的label。这时候根据投票来确定,或者填充缺失值。
分类和回归
实际应用中,决策树有分类树和回归树两种,前者用于预测类别,例如是否健康,能否偿还贷款,后者用于预测实数值,例如温度,健康程度等。
分类树:
树在构建过程中或者按照阈值设定,或者按照类别将样本划分到多个子分支中,直到某一个分支中的所有样本属于同一个类别,即最纯,或者属性已经用完了,或者达到预先设置的条件,这个分支就停止划分了,并成为叶子节点,它的类别采用的是多人投票法,即哪种类别最多,即为那个类别。
回归树:
回归树与分类树类似,不过由于预测的值为连续值,没有类别的概念,也就是说我们无法计算分支节点的纯度,因此我们不再使用最大化信息增益来作为划分选择,而是采用最小化均方误差(回想前面所讲的线性回归中的公式)
J
=
1
m
∑
i
=
1
m
(
y
i
‾
−
y
)
2
J = \frac{1}{m}\sum_{i=1}^{m} (\overline{y_i} - y) ^2
J=m1i=1∑m(yi−y)2
其中
y
i
‾
\overline{y_i}
yi为预测值,
y
y
y为实际值,
m
m
m为样本数,
J
J
J为误差。
我们对于每一个分支节点都计算了一个预测值,它为这个分支节点所有预测值的平均值。
分枝时穷举每一个feature的每个阈值找最好的分割点,以最小化均方误差。当进行预测的时候,以该节点所有人的平均年龄作为该节点的预测值。
参考资料
https://www.cnblogs.com/wxquare/p/5379970.html
https://www.cnblogs.com/bourneli/p/2961568.html
http://blog.csdn.net/dark_scope/article/details/13168827
https://www.cnblogs.com/leoo2sk/archive/2010/09/19/decision-tree.html
https://www.zhihu.com/question/34867991/answer/151775210