机器学习基础 - 决策树算法

机器学习基础 - 决策树算法

1. 本章的主要学习内容为

  • 决策树:决策树、信息熵与最优划分、基尼系数、CART
  • 实现:决策树实现

2. 初始决策树

决策树是一个非常有意思的模型,它的建模思路是尽可能模拟人做决策的过程。因此决策树几乎没有任何抽象,完全通过生成决策规则来解决分类和回归问题。因为它的运行机制能很直接地被翻译成人类语言,即使对建模领域完全不了解的非技术人员也能很好地理解它。因此在学术上被归为白盒模型(white box model)。

2.1 什么是决策树

决策树是一种常见的机器学习算法,它的思想十分朴素,类似于我们平时利用选择做决策的过程。它是类似流程图的结构,其中每个内部节点表示一个测试功能,即类似做出决策的过程(动作),每个叶节点都表示一个类标签,即在计算所有特征之后做出的决定(结果)。标签和分支表示导致这些类标签的功能的连接。从根到叶的路径表示分类规则。比如下面这个“相亲决策树”:
机器学习基础 - 决策树算法_第1张图片
由此我们可以看到,决策树的思想还是非常直观的。
用决策树分类:从根节点开始,对实例的某一特征进行测试,根据测试结果将实例分配到其子节点,此时每个子节点对应着该特征的一个取值,如此递归的对实例进行测试并分配,直到到达叶节点,最后将实例分到叶节点的类中。

2.2 决策树的本质

决策树学习本质上是从训练数据集中归纳出一组分类规则。与训练数据集不相矛盾的决策树(即能对训练数据进行正确分类的决策树)可能是0个或多个。我们需要找到一个与训练数据矛盾较小的决策树,同时具有很好的泛化能力。
从另一个角度看,决策树学习是由训练数据集估计条件概率模型。基于特征空间划分的类的条件概率模型有无穷多个。我们选择的条件概率模型应该不仅对训练数据有很好地拟合,而且对未知数据有很好地预测。

2.3 决策树的损失函数

与其他模型相同,决策树学习用损失函数表示这一目标。决策树学习的损失函数通常是正则化的极大似然函数。决策树学习的策略是以损失函数为目标函数的最小化。

关于极大似然函数:极大似然法是属于数理统计范畴,旨在由果溯因。把“极大似然估计”拆成三个词:极大(最大的概率)、似然(看起来是这个样子的)、估计(就是这个样子的),连起来就是:大概率看起来是这样的,那就是这样。
比如扔一枚骰子(骰子每个面上只标记1或2),现在告诉你扔了n次骰子其中有k次朝上的是1;然后问你这个骰子标记为1的面所占的比例w是多少?极大似然法的思想就是估计当w取值为多少的时候,k次朝上的可能性最大。具体计算方法就是对表达式求最大值,得到参数值估计值:一般就是对这个表达式求一阶导=0(二阶导<0);
这就是极大似然估计方法的原理:用使概率达到最大的那个概率值w来估计真实参数w。决策树生成的过程可以理解成对决策树模型的参数估计(就是基于特征空间划分的类的概率模型),根据训练数据的特征分布,选择使得模型最契合当前样本分布空间时的条件概率模型。

当损失函数确定以后,学习问题就变为在损失函数意义下选择最优决策树的问题。因为从所有可能的决策树中选取最优决策树是NP完全问题,所以现实中决策树学习算法通常采用启发式方法,近似求解这一最优化问题。这样得到的决策树是次最优的。

2.4 决策树的构建

决策树通常有三个步骤:

  • 特征选择
  • 决策树的生成
  • 决策树的修剪

决策树学习的算法通常是一个递归地选择最优特征,并根据该特征对训练数据进行分割,使得对各个子数据集有一个最好的分类的过程。这一过程对应着对特征空间的划分,也对应着决策树的构建。
这一过程对应着对特征空间的划分,也对应着决策树的构建。

  1. 开始:构建根节点,将所有训练数据都放在根节点,选择一个最优特征,按照这一特征将训练数据集分割成子集,使得各个子集有一个在当前条件下最好的分类。
  2. 如果这些子集已经能够被基本正确分类,那么构建叶节点,并将这些子集分到所对应的叶子节点去。
  3. 如果还有子集不能够被正确的分类,那么就对这些子集选择新的最优特征,继续对其进行分割,构建相应的节点,如此递归进行,直至所有训练数据子集被基本正确的分类,或者没有合适的特征为止。
  4. 每个子集都被分到叶节点上,即都有了明确的类,这样就生成了一颗决策树。

以上方法就是决策树学习中的特征选择和决策树生成,这样生成的决策树可能对训练数据有很好的分类能力,但对未知的测试数据却未必有很好的分类能力,即可能发生过拟合现象。我们需要对已生成的树自下而上进行剪枝,将树变得更简单,从而使其具有更好的泛化能力。具体地,就是去掉过于细分的叶结点,使其回退到父结点,甚至更高的结点,然后将父结点或更高的结点改为新的叶结点,从而使得模型有较好的泛化能力。。
决策树生成和决策树剪枝是个相对的过程,决策树生成旨在得到对于当前子数据集最好的分类效果(局部最优),而决策树剪枝则是考虑全局最优,增强泛化能力。
在对此有一定了解之后,我们先看看,如何在sklearn中将决策树用起来。然后再学习其中的细节。

2.5 在sklearn中使用决策树

数据引入及可视化

import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets

iris = datasets.load_iris()
X = iris.data[:,2:] # iris有四个特征,这里取后两个,形成一个坐标点
y = iris.target
# 绘图
plt.scatter(X[y==0,0],X[y==0,1])
plt.scatter(X[y==1,0],X[y==1,1])
plt.scatter(X[y==2,0],X[y==2,1])
plt.show()

机器学习基础 - 决策树算法_第2张图片
进行分类

from sklearn.tree import DecisionTreeClassifier
# 创建决策树对象,最大深度max_depth为2层,criterion评判标准为entropy(熵)
dt_clt = DecisionTreeClassifier(max_depth=2,criterion='entropy')
# 将训练数据送给模型
dt_clt.fit(X,y)

# 绘制决策边界
def plot_decision_boundary(model, axis): # 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)

    from matplotlib.colors import ListedColormap
    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[y==0,0],X[y==0,1])
plt.scatter(X[y==1,0],X[y==1,1])
plt.scatter(X[y==2,0],X[y==2,1])
plt.show()

机器学习基础 - 决策树算法_第3张图片
对于上图的数据可视化结果,我们可以直观地看到。y=1.75这条直线为一条决策边界,y大于1.75属于A类;y小于1.75的区域,被y=0.8划分,y<1.75||y>0.8属于B类;y<0.8属于C类。
决策树是一个非参数的决策算法,决策树可以解决分类问题,且天然支持多分类问题。决策树也可以解决回归问题,按照树的路径追踪到叶子结点,最终叶子节点对应一个数值,且回归问题的结果是一个具体的数值,就可以落在叶子结点的所有样本的平均值,作为回归的预测结果。
并且决策树具有非常好的可解释性。
那么提出一个问题:在构建决策树,进行特征选择划分时,究竟选择哪个特征更好些?
这就要求确定选择特征的准则。直观上,如果一个特征具有更好的分类能力,或者说,按照这一特征将训练数据集分割成子集,使得各个子集在当前条件下有最好的分类,那么就更应该选择这个特征。比如身高、长相、收入等。在找到特征维度之后,还要确定划分阈值,如收入定在多少,作为划分标准比较合适?
因此,首先找到一个维度,然后在维度上找到一个阈值。然后以这个维度的这个阈值为依据进行划分。核心问题是:
每个节点在哪个维度做划分?选好了维度,如何确定阈值呢?

3. 特征选择中的相关概念

特征选择,就是决策树的构造过程。
为了找到最优的划分特征,我们需要先了解一些信息论的知识。

  • 信息熵(information entropy)
  • 条件熵(conditional entropy)
  • 信息增益(information gain)
  • 信息增益率(information gain ratio)
  • 基尼指数(Gini index)

3.1 信息熵

熵是热力学中的概念,表示混乱程度。熵越大,热力系统中粒子无规则的运动越剧烈;熵越小,粒子越趋近于静止的状态。
引申到信息论和概率统计中,信息熵表示随机变量的不确定度。对于一组数据来说,越随机、不确定性越高,信息熵越大;不确定性越低,信息熵越小。为了计算熵,我们需要计算所有类别所有可能值所包含的信息期望值,著名的香农公式:
在这里插入图片描述

3.2 条件熵

设有随机变量(X, Y)。条件熵H(Y|X)表示在已知随机变量X的条件下随机变量Y的不确定性。
在这里插入图片描述
注意,与信息熵不同的是,条件熵是数学期望,而不是变量的不确定性。

3.3 信息增益

在划分数据集前后信息发生的变化称为信息增益,获得信息增益最高的特征就是最好的选择。
信息增益就是:
以某特征划分数据集前后的熵的差值
机器学习基础 - 决策树算法_第4张图片
通过对信息增益的进一步理解,我们发现:对于待划分的数据集D,其经验熵H(D)是不变的,但是划分之后得到的条件熵H(D|A)是变化的(特征A的选择不同)。
条件熵H(D|A)越小,说明使用此特征划分得到的子集的不确定性越小(也就是纯度越高),因为得到的信息增益就越大。说明在决策树构建的过程中我们总是希望集合往最快到达纯度更高的子集合方向发展,因此我们总是选择使得信息增益最大的特征来划分当前数据集D。
信息增益偏向取值较多的特征。
原因:当特征的取值较多时,根据此特征划分更容易得到纯度更高的子集,因此划分之后的熵更低,由于划分前的熵是一定的,因此信息增益更大,因此信息增益比较偏向取值较多的特征。

3.4 信息增益率的定义

特征A对训练数据集D的信息增益比定义为:其信息增益g(D,A)与训练数据集D关于特征A的值的熵HA(D)之比,即:
在这里插入图片描述
信息增益比本质:是在信息增益的基础之上乘上一个惩罚参数。特征个数较多时,惩罚参数较小;特征个数较少时,惩罚参数较大。
信息增益比 = 惩罚参数 * 信息增益
所谓惩罚参数,是数据集D以特征A作为随机变量的熵的倒数,即:将特征A取值相同的样本划分到同一个子集中(之前所说数据集的熵是依据类别进行划分的)。
信息增益比的缺点是:偏向取值较少的特征。原因:当特征取值较少时HA(D)的值较小,因此其倒数较大,因而信息增益比较大。因而偏向取值较少的特征。
基于以上特点,在使用增益信息比时,并不是直接选择信息增益率最大的特征,而是现在候选特征中找出信息增益高于平均水平的特征,然后在这些特征中再选择信息增益率最高的特征。

3.5 基尼系数

基尼系数(Gini),也被称为基尼不纯度,表示在样本集合中一个随机选中的样本被分错的概率。
Gini系数越小表示集合中被选中的样本被分错的概率越小,也就是说集合的纯度越高,反之,基尼指数集合越不纯。
即:基尼指数(基尼不纯度)= 样本被选中的概率 * 样本被分错的概率
有如下公式:
在这里插入图片描述
对上述公式进行说明:
表示选中的样本属于k类别的概率,则这个样本被分错的概率是(1-pk)
因为样本集合中有k个类别,一个随机选中的样本可以属于这k个类别中的任意一个,因而累加所有的k个类别。
当二分类时,G=2p(1-p)
机器学习基础 - 决策树算法_第5张图片

4. 剪枝

当训练数据量大、特征数量较多时构建的决策树可能很庞大,这样的决策树用来分类是否好?答案是否定的。
决策树是依据训练集进行构建的,为了尽可能正确地分类训练样本,结点划分过程将不断重复,有时会造成决策树分支过多。这就可能会把训练样本学的“太好”了,以至于把训练集自身的一些特点当作所有数据都具有的一般性质而导致过拟合。因此可主动去掉一些分支来降低过拟合风险。
决策树非常容易产生过拟合,实际所有非参数学习算法,都非常容易产生过拟合。
因此,对于决策树的构建还需要最后一步,即决策树的修剪。两个目的:降低复杂度,解决过拟合。
决策树的修剪,也就是剪枝操作,主要分为两种:

  • 预剪枝(Pre-Pruning)
  • 后剪枝(Post-Pruning)

接下来我们将详细地介绍这两种剪枝方法。

预剪枝是指在决策树生成过程中,对每个节点在划分前先进行估计,若当前节点的划分不能带来决策树泛化性能的提升,则停止划分并将当前节点标记为叶节点。
那么所谓的“决策树泛化性能”如何来判定呢?这就可以使用性能评估中的留出法,即预留一部分数据用作“验证集”以进行性能评估。
后剪枝是先从训练集生成一颗完整的决策树,然后自底向上地对非叶节点进行考察,若将该节点对应的子树完全替换为叶节点能带来决策树繁花性的提升,则将该子树替换为叶节点。
对比预剪枝和后剪枝,能够发现,后剪枝决策树通常比预剪枝决策树保留了更多的分支,一般情形下,后剪枝决策树的欠拟合风险小,泛华性能往往也要优于预剪枝决策树。但后剪枝过程是在构建完全决策树之后进行的,并且要自底向上的对树中的所有非叶结点进行逐一考察,因此其训练时间开销要比未剪枝决策树和预剪枝决策树都大得多。

4.1 Sklearn 实现

sklearn.tree:提供了决策树模型,用于解决分类和回归问题。

class sklearn.tree.DecisionTreeClassifier(criterion=’gini’, splitter=’best’, max_depth=None, min_samples_split=2, min_samples_leaf=1, min_weight_fraction_leaf=0.0, max_features=None, random_state=None, max_leaf_nodes=None, min_impurity_decrease=0.0, min_impurity_split=None, class_weight=None, presort=False)[source]

参数说明如下:
criterion:特征选择标准,可选参数,默认是gini,可以设置为entropy。gini是基尼不纯度,是将来自集合的某种结果随机应用于某一数据项的预期误差率,是一种基于统计的思想。entropy是香农熵,也就是上篇文章讲过的内容,是一种基于信息论的思想。Sklearn把gini设为默认参数,应该也是做了相应的斟酌的,精度也许更高些?ID3算法使用的是entropy,CART算法使用的则是gini。
splitter:特征划分点选择标准,可选参数,默认是best,可以设置为random。每个结点的选择策略。best参数是根据算法选择最佳的切分特征,例如gini、entropy。random随机的在部分划分点中找局部最优的划分点。默认的”best”适合样本量不大的时候,而如果样本数据量非常大,此时决策树构建推荐”random”。
max_features:划分时考虑的最大特征数,可选参数,默认是None。寻找最佳切分时考虑的最大特征数(n_features为总共的特征数),有如下6种情况:
如果max_features是整型的数,则考虑max_features个特征;
如果max_features是浮点型的数,则考虑int(max_features * n_features)个特征;
如果max_features设为auto,那么max_features = sqrt(n_features);
如果max_features设为sqrt,那么max_featrues = sqrt(n_features),跟auto一样;
如果max_features设为log2,那么max_features = log2(n_features);
如果max_features设为None,那么max_features = n_features,也就是所有特征都用。一般来说,如果样本特征数不多,比如小于50,我们用默认的”None”就可以了,如果特征数非常多,我们可以灵活使用刚才描述的其他取值来控制划分时考虑的最大特征数,以控制决策树的生成时间。
max_depth:决策树最大深,可选参数,默认是None。这个参数是这是树的层数的。层数的概念就是,比如在贷款的例子中,决策树的层数是2层。如果这个参数设置为None,那么决策树在建立子树的时候不会限制子树的深度。一般来说,数据少或者特征少的时候可以不管这个值。或者如果设置了min_samples_slipt参数,那么直到少于min_smaples_split个样本为止。如果模型样本量多,特征也多的情况下,推荐限制这个最大深度,具体的取值取决于数据的分布。常用的可以取值10-100之间。
min_samples_split:内部节点再划分所需最小样本数,可选参数,默认是2。这个值限制了子树继续划分的条件。如果min_samples_split为整数,那么在切分内部结点的时候,min_samples_split作为最小的样本数,也就是说,如果样本已经少于min_samples_split个样本,则停止继续切分。如果min_samples_split为浮点数,那么min_samples_split就是一个百分比,ceil(min_samples_split * n_samples),数是向上取整的。如果样本量不大,不需要管这个值。如果样本量数量级非常大,则推荐增大这个值。
min_weight_fraction_leaf:叶子节点最小的样本权重和,可选参数,默认是0。这个值限制了叶子节点所有样本权重和的最小值,如果小于这个值,则会和兄弟节点一起被剪枝。一般来说,如果我们有较多样本有缺失值,或者分类树样本的分布类别偏差很大,就会引入样本权重,这时我们就要注意这个值了。
max_leaf_nodes:最大叶子节点数,可选参数,默认是None。通过限制最大叶子节点数,可以防止过拟合。如果加了限制,算法会建立在最大叶子节点数内最优的决策树。如果特征不多,可以不考虑这个值,但是如果特征分成多的话,可以加以限制,具体的值可以通过交叉验证得到。
class_weight:类别权重,可选参数,默认是None,也可以字典、字典列表、balanced。指定样本各类别的的权重,主要是为了防止训练集某些类别的样本过多,导致训练的决策树过于偏向这些类别。类别的权重可以通过{class_label:weight}这样的格式给出,这里可以自己指定各个样本的权重,或者用balanced,如果使用balanced,则算法会自己计算权重,样本量少的类别所对应的样本权重会高。当然,如果你的样本类别分布没有明显的偏倚,则可以不管这个参数,选择默认的None。
random_state:可选参数,默认是None。随机数种子。如果是证书,那么random_state会作为随机数生成器的随机数种子。随机数种子,如果没有设置随机数,随机出来的数与当前系统时间有关,每个时刻都是不同的。如果设置了随机数种子,那么相同随机数种子,不同时刻产生的随机数也是相同的。如果是RandomState instance,那么random_state是随机数生成器。如果为None,则随机数生成器使用np.random。
min_impurity_split:节点划分最小不纯度,可选参数,默认是1e-7。这是个阈值,这个值限制了决策树的增长,如果某节点的不纯度(基尼系数,信息增益,均方差,绝对差)小于这个阈值,则该节点不再生成子节点。即为叶子节点 。
presort:数据是否预排序,可选参数,默认为False,这个值是布尔值,默认是False不排序。一般来说,如果样本量少或者限制了一个深度很小的决策树,设置为true可以让划分点选择更加快,决策树建立的更加快。如果样本量太大的话,反而没有什么好处。问题是样本量少的时候,我速度本来就不慢。所以这个值一般懒得理它就可以了。
除了这些参数要注意以外,其他在调参时的注意点有:
当样本数量少但是样本特征非常多的时候,决策树很容易过拟合,一般来说,样本数比特征数多一些会比较容易建立健壮的模型如果样本数量少但是样本特征非常多,在拟合决策树模型前,推荐先做维度规约,比如主成分分析(PCA),特征选择(Losso)或者独立成分分析(ICA)。这样特征的维度会大大减小。再来拟合决策树模型效果会好。
推荐多用决策树的可视化,同时先限制决策树的深度,这样可以先观察下生成的决策树里数据的初步拟合情况,然后再决定是否要增加深度。
在训练模型时,注意观察样本的类别情况(主要指分类树),如果类别分布非常不均匀,就要考虑用class_weight来限制模型过于偏向样本多的类别。
决策树的数组使用的是numpy的float32类型,如果训练数据不是这样的格式,算法会先做copy再运行。
如果输入的样本矩阵是稀疏的,推荐在拟合前调用csc_matrix稀疏化,在预测前调用csr_matrix稀疏化。

5. 分类与回归树CART

待续

你可能感兴趣的:(机器学习,机器学习,决策树)