目录
1. 学习内容
1. 决策树的概念及核心思想
2. 决策树的学习过程
3. 如何选择特征进行划分
4. 利用ID3和C4.5来构建决策树
5. 用sklearn实现决策树
6. 分类与回归树CART
2. 决策树的基本概念
2.1 什么是决策树
如果你对流程图比较了解的话,那么决策树就相当于是一个只含有“开始”、“结束”和“判断”的树状流程图。决策树是一个非常有意思的模型,它的建模思路是尽可能模拟人做决策的过程。因此决策树几乎没有任何抽象,完全通过生成决策规则(即判断次序和判断条件)来解决分类和回归问题的。
相对于其他的机器学习算法而言,决策树有一个十分鲜明的特点就是它具有“可解释性”。换句话说,当一棵决策树被生成之后,我们可以通过得到的结果反推这个模型从数据输入得到这个结果的全过程。而其他模型,尤其是神经网络,在这方面表现的并不好,甚至很糟糕。
决策树还是一个非参数的决策算法,它本身就支持多分类问题。而且,决策树模型也可以用来解决回归问题。当按照树的路径追踪到叶子结点,取最终叶子节点中的所有样本的平均值作为回归的预测结果。
2.2 决策树与条件概率
决策树表示给定特征条件下,类的条件概率分布,这个条件概率分布表示在特征空间的划分上,将特征空间根据各个特征值不断进行划分,就将特征空间分为了多个不相交的单元,在每个单元定义了一个类的概率分布,这样,这条由根节点到达叶节点的路径就成了一个条件概率分布。
假设X表示特征的随机变量,Y表示类的随机变量,那么这个条件概率可以表示为,其中X取值于给定划分下单元的集合,Y取值于类的集合。各叶结点(单元)上的条件概率往往偏向某一个类。根据输入的测试样本,由路径找到对应单元的各个类的条件概率,并将该输入测试样本分为条件概率最大的一类中,就可以完成对测试样本的分类[1]。
2.3 决策树学习的本质
决策树学习本质上是从训练数据集中归纳出一组分类规则。与训练数据集不矛盾的决策树(即能对训练数据进行不重不漏分类的决策树)可能是0个或多个。我们需要找到一个与训练数据矛盾较小的决策树,同时具有很好的泛化能力(即预防欠拟合和过拟合)。
从另一个角度看,决策树学习是由训练数据集估计条件概率模型。基于特征空间划分的类的条件概率模型有无穷多个。我们选择的条件概率模型应该不仅对训练数据有很好的拟合效果,而且对未知数据有很好的预测效果[1]。
3. 决策树构建的基本方法
决策树的构建主要分成三个步骤:特征选取、生成和修剪。决策树学习的算法通常是一个递归地选择最优特征,并根据该特征对训练数据进行分割,使得对各个子数据集有一个最好的分类的过程。这一过程对应着对特征空间的划分,也对应着决策树的构建。具体的步骤如下[1]:
1. 构建根节点,将所有训练数据都放在根节点,选择一个最优特征,按照这一特征将训练数据集分割成子集,使得各个子集有一个在当前条件下最好的分类;
2. 如果这些子集已经能够被基本正确分类,那么构建叶节点,并将这些子集分到所对应的叶子节点去;
3. 如果还有子集不能够被正确的分类,那么就对这些子集选择新的最优特征,继续对其进行分割,构建相应的节点。如此递归进行,直至所有训练数据子集被基本正确的分类,或者没有合适的特征为止;
4. 每个子集都被分到叶节点上,即都有了明确的类。这样就生成了一颗决策树。
需要注意的是,最优决策树的生成问题是一个NP完全问题。当特征非常多的时候,生成一棵最优决策树的时间是很长的。因此,在进行特征选择时往往采用的是贪心算法或者启发式算法。
另外,修剪的目的是防止出现过拟合的情况。具体地,就是去掉过于细分的叶结点,使其回退到父结点,甚至更高的结点,然后将父结点或更高的结点改为新的叶结点,从而使得模型有较好的泛化能力。
4. 用sklearn中的决策树相关模块进行分类
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.tree import DecisionTreeClassifier
from matplotlib.colors import ListedColormap
iris = datasets.load_iris()
# iris有四个特征,这里取后两个,形成一个坐标点
X = iris.data[:, 2:]
y = iris.target
# 创建决策树对象,最大深度max_depth为2层,criterion评判标准为entropy(熵)
dt_clt = DecisionTreeClassifier(max_depth = 2,criterion = 'entropy')
dt_clt.fit(X, y)
# 绘制决策边界
# model是模型,axis是范围
def plot_decision_boundary(model, axis):
x0, x1 = np.meshgrid(
np.linspace(axis[0], axis[1], int((axis[1] - axis[0]) * 100)).reshape(-1, 1),
np.linspace(axis[2], axis[3], int((axis[3] - axis[2]) * 100)).reshape(-1, 1),
)
X_new = np.c_[x0.ravel(), x1.ravel()]
y_predict = model.predict(X_new)
zz = y_predict.reshape(x0.shape)
custom_cmap = ListedColormap(['#EF9A9A','#FFF59D','#90CAF9'])
plt.contourf(x0, x1, zz, linewidth = 5, cmap = custom_cmap)
plot_decision_boundary(dt_clt, axis = [0.5, 7.5, 0, 3])
plt.scatter(X[:, 0], X[:, 1], c = y)
plt.show()

对于上图的数据可视化结果,我们可以直观地看到。y=1.75这条直线为一条决策边界,y大于1.75属于A类;y小于1.75的区域,被y=0.8划分,y<1.75且y>0.8属于B类;y<0.8属于C类。
5. 决策树模型的构建
5.1 特征选择
决策树既然是一棵以特征为中间节点的树,那么这棵树中间节点就有很多的组合方式。由于得到所有的组合方式是一个NP完全问题,因此特征越多用时越长且越无法令人接受。所以,实际情况中往往会利用贪心算法或其他启发式算法来选取合适的特征构建决策树。
通常,在决策树中,一个优先考虑的特征一定是满足信息(熵)增益最大的特征。信息增益指的是以某特征划分数据集前后的信息熵的差值。
熵是热力学中的概念,表示混乱程度。熵越大,热力系统中粒子无规则的运动越剧烈;熵越小,粒子越趋近于静止的状态。在信息论和概率统计中,信息熵表示随机变量的不确定度。对于一组数据来说,越随机、不确定性越高,信息熵越大;不确定性越低,信息熵越小。为了计算信息熵,我们需要计算所有类别所有可能值所包含的信息期望值。这里需要用到著名的香农公式:
假设共有k个类别,选取到第i个类别的概率为,则整个系统的熵就是H。
因此,一个简单的特征选取方法就是:从特征集合中依次选取使得当前树的信息增益最大的特征。这实际上就是一种贪心算法(ID3算法)。具体的解释和实例以及其他的标准可以参考[2][3]。
不过需要说明的是信息增益总是偏向于选择取值较多的属性。为了解决这个问题,引入了另外一个概念叫做信息增益比。信息增益比在信息增益的基础上增加了一个罚项。
5.2 决策树的生成
5.2.1 ID3算法
ID3算法是一种分类预测算法,算法以信息论中的“信息增益”为基础。核心是通过计算每个特征的信息增益,每次划分选取信息增益最高的属性为划分标准,递归地构建决策树[4]。
ID3相当于用极大似然法进行概率模型的选择。
具体方法是:
1. 从根结点(root node)开始,对结点计算所有可能的特征的信息增益,选择信息增益最大的特征作为结点的特征;
2. 由该特征的不同取值建立子节点,再对子结点递归地调用以上方法,构建决策树;直到所有特征的信息增益均很小或没有特征可以选择为止;
3. 最后得到一个决策树。
该算法的优点是:
1. 决策树易于理解和实现. 人们在通过解释后都有能力去理解决策树所表达的意义;
2. 对于决策树,数据的准备往往是简单或者是不必要的 . 其他的技术往往要求先把数据一般化,比如去掉多余的或者空白的属性;
3. 能够同时处理数据型和常规型属性。其他的技术往往要求数据属性的单一;
4. 是一个白盒模型如果给定一个观察的模型,那么根据所产生的决策树很容易推出相应的逻辑表达式;
5. 易于通过静态测试来对模型进行评测。表示有可能测量该模型的可信度;
6. 在相对短的时间内能够对大型数据源做出可行且效果良好的结果。
缺点是:
1. 没有剪枝过程,为了去除过渡数据匹配的问题,可通过裁剪合并相邻的无法产生大量信息增益的叶子节点;
2. 信息增益的方法偏向选择具有大量值的属性,也就是说某个属性特征所取的不同值越多,那么越有可能作为分裂属性,这样是不合理的;
3. 只可以处理离散分布的数据特征;
4. ID3算法只考虑了树的生成,即尽可能的是模型拟合当前训练数据集,所以该算法生成的决策树容易过拟合。
5.2.2 C4.5算法
C4.5算法相当于是对ID3算法的改进,改进之处如下:
2. 在决策树的构造过程中对树进行剪枝;
3. 对非离散数据也能处理;
4. 能够对不完整数据进行处理。
C4.5算法处理连续特征是先将特征取值排序,以连续两个值中间值作为划分标准。尝试每一种划分,并计算修正后的信息增益,选择信息增益最大的分裂点作为该属性的分裂点[4]。
5.3 决策树的修剪
决策树非常容易产生过拟合。实际上,所有的非参数学习算法,都非常容易产生过拟合。因此,对于决策树的构建还需要最后一步,即决策树的修剪。修剪不但可以削弱过拟合,还可以降低复杂度。
决策树的修剪无外乎两种操作:预剪枝和后剪枝。
预剪枝是指在决策树生成过程中,对每个节点在划分前先进行估计,若当前节点的划分不能带来决策树泛化性能的提升,则停止划分并将当前节点标记为叶节点。那么所谓的“决策树泛化性能”如何来判定呢?这就可以使用性能评估中的留出法,即预留一部分数据用作“验证集”以进行性能评估。具体实例可以参考[5]。
后剪枝是先从训练集生成一颗完整的决策树,然后自底向上地对非叶节点进行考察,若将该节点对应的子树完全替换为叶节点能带来决策树泛化性的提升,则将该子树替换为叶节点。
对比预剪枝和后剪枝可以发现:后剪枝决策树通常比预剪枝决策树保留了更多的分支。一般情形下,后剪枝决策树的欠拟合风险小,泛化性能往往也要优于预剪枝决策树。但后剪枝过程是在构建完全决策树之后进行的,并且要自底向上的对树中的所有非叶结点进行逐一考察,因此其训练时间开销要比未剪枝决策树和预剪枝决策树都大得多。
sklearn中现在只能做预剪枝,就是设置Classifier或者Regression里的参数max_depth, min_samples_split, min_samples_leaf。而后剪枝在sklearn中是做不到的。至于分类和回归还有哪些参数,可以参考[5]。
6. 分类与回归树(CART)
CART算法(Classification And Regression Tree),顾名思义,是既可以用于创建分类树,也可以用于创建回归树的算法。既可以解决分类问题,也可以解决回归问题。它会根据某一个维度d和某一个阈值v进行二分,得到的决策树是二叉树。
ID3中使用了信息增益选择特征,增益大优先选择。C4.5中,采用信息增益比选择特征,减少因特征值多导致信息增益大的问题。CART分类树算法使用基尼系数来代替信息增益比,基尼系数代表了模型的不纯度,基尼系数越小,不纯度越低,特征越好。这和信息增益(比)相反。
由于CART的输入特征既可以是离散值,又可以是连续值。
对于离散值,CART会不断进行二分。在ID3、C4.5,特征A被选取建立决策树节点,如果它有3个类别A1,A2,A3,我们会在决策树上建立一个三叉点,这样决策树是多叉树。CART采用的是不停的二分。会考虑把特征A分成{A1}和{A2,A3}、{A2}和{A1,A3}、{A3}和{A1,A2}三种情况,找到基尼系数最小的组合。比如{A2}和{A1,A3},然后建立二叉树节点,一个节点是A2对应的样本,另一个节点是{A1,A3}对应的样本。由于这次没有把特征A的取值完全分开,各分支下的子数据集必须依旧包含该特征,该连续特征在接下来的树分支过程中可能依旧起着决定性作用。因此后面还有机会对子节点继续选择特征A划分A1和A3。这和ID3、C4.5不同,在ID3或C4.5的一颗子树中,离散特征只会参与一次节点的建立[6]。
CART分类树算法对连续值的处理,思想和C4.5相同,都是将连续的特征离散化。唯一区别在选择划分点时,C4.5是信息增益比,CART是基尼系数。另外,如果当前节点为连续属性,则该属性在后面还可以参与子节点的产生选择过程。
另外,CART采用的是后剪枝法来进行剪枝的。
7. 参考文献
1. https://mp.weixin.qq.com/s/k_OjObExgsi4DaHMSGUUMA
2. https://mp.weixin.qq.com/s/yFxysYAx2Fe--11kJ4M3tg
3. https://mp.weixin.qq.com/s/lP5ZqfhDCd4Tt3IYpQm-Lg
4. https://mp.weixin.qq.com/s/poI_7bBnoxgIciaIQYB_Iw