机器学习实战6-sklearn训练决策树实现分类和回归

  简介:

     与SVM一样,决策树也是一种多功能的机器学习算法,它可以实现分类和回归任务,甚至是多输出任务。它们功能强大,能够拟合复杂的数据集。决策树同时也是随机森林(参见第7章)的基本组成部分,后者是现今最强大的机器学习算法之一。
     首先,我们会讨论如何对决策树进行训练、可视化和预测;然后介绍Scikit-Learn的CART训练算法,讨论如何对决策树进
行正则化并将其用于回归任务;最后,我们会谈一谈决策树的局限性。 

一个决策树实例:

1、构建一个决策树

看看它是如何做出预测的。下面的代码在鸢尾花数据集上训练了一个DecisionTreeClassifier:

(Scikit-Learn使用的是CART算法,该算法仅生成二叉树:非叶节点永远只有两个子节点(即问题答案仅有是或否)。但是,其他
算法,比如ID3生成的决策树,其节点可以拥有两个以上的子节点)

from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier
iris=load_iris()
X=iris.data[:,2:]
y=iris.target
tree_clf=DecisionTreeClassifier(max_depth=2,random_state=42)
tree_clf.fit(X,y)

 输出一个树结构:

DecisionTreeClassifier(class_weight=None, criterion='gini', max_depth=2,
            max_features=None, max_leaf_nodes=None,
            min_impurity_decrease=0.0, min_impurity_split=None,
            min_samples_leaf=1, min_samples_split=2,
            min_weight_fraction_leaf=0.0, presort=False, random_state=42,
            splitter='best')
tree.DecisionTreeClassifier(class_weight=None, #balanced & None 可选
                            criterion='gini',#"gini"或者"entropy",前者代表基尼系数,后者代表信息增益。
                            max_depth=None,#max_depth控制树的深度防止overfitting
            max_features=None, #可使用多种类型值,默认是"None",划分时考虑所有的特征数;
                               #"log2" 划分时最多考虑log2Nlog2N个特征;
                               #"sqrt"或者"auto" 划分时最多考虑√N个特征。
                               #整数,代表考虑的特征绝对数。
                               #浮点数,代表考虑特征百分比,即考虑(百分比xN)取整后的特征数。
                               #其中N为样本总特征数。
            max_leaf_nodes=None,#最大叶节点树
            min_impurity_split=1e-07, #限制决策树的增长,
                            #如果某节点的不纯度(基尼系数,信息增益)小于这个阈值,则该节点不再生成子节点,即为叶子节点。 
            min_samples_leaf=1,min_samples_split=2,#min_samples_split或min_samples_leaf来控制叶节点上的样本数量;
            #两者之间的主要区别在于min_samples_leaf保证了叶片中最小的样本数量,而min_samples_split可以创建任意的小叶子。但min_samples_split在文献中更常见。
            min_weight_fraction_leaf=0.0,#限制叶子节点所有样本权重和的最小值。如果小于这个值,则会和兄弟节点一起被剪枝。
                            # 默认是0,就是不考虑权重问题。
                            #一般来说,如果我们有较多样本有缺失值,或者分类树样本的分布类别偏差很大,
                            #就会引入样本权重,这时我们就要注意这个值了。
            presort=False,#布尔值,默认是False不排序。预排序,提高效率。
                          #设置为true可以让划分点选择更加快,决策树建立的更加快。
            random_state=None, #随机生成器种子设置,默认设置为None,如此,则每次模型结果都会有所不同。
            splitter='best')#split"best"或者"random"。
           #前者在特征的所有划分点中找出最优的划分点。
           #后者是随机的在部分划分点中找局部最优的划分点。
           #默认的"best"适合样本量不大的时候,而如果样本数据量非常大,此时决策树构建推荐"random"。

参数详情:https://blog.csdn.net/qq_30815237/article/details/89218316 

                      

参数说明:

     samples属性:统计它应用的训练实例数量。例如,有100个训练实例的花瓣长度大于2.45厘米(深度1,右),其中54个花瓣宽度小于1.75厘米(深度2,左)。

    value属性:说明了该节点上每个类别的训练实例数量:例如,右下节点应用在0个Setosa鸢尾、1个Versicolor鸢尾和45个Virginica鸢尾实例上。

    class属性:说明该节点的类别。

    节点的gini属性:衡量其不纯度(impurity):如果应用的所有训练实例都属于同一个类别,那么节点就是“纯”的(gini=0)。例如,深度1左侧节点仅应用于Setosa鸢尾花训练实例,所以它就是纯的,并且gini值为0。

基尼不纯度:
                                            G_{i}=1-\sum ^{n}_{k=1}p_{i,k}^{2}

其中:p_{i,k}是第i个节点上,类别为k的训练实例占比。

例如,深度2左侧节点,基尼系数等于    1–(0/54)^2 –(49/54)^2 –(5/54)^2 ≈0.168。

决策树的特质之一就是它们需要的数据准备工作非常少。完全不需要进行特征缩放或集中。

如何做出预测?
        以上图中的树为例,如果你找到了一朵鸢尾花,想要将其归类,那么从根节点(深度0,位于顶部)开始:这朵花的花瓣长度是否小于2.45厘米?如果是,则向下移动到根的左侧子节点(深度1,左)。本例中,这是一个叶节点(即没有任何子节点),所以它不再继续提出问题,你可以直接查看这个节点的预测类别,也就是说,决策树预测你的这朵花是Setosa鸢尾花(class=setosa)。
        假设你又找到了一朵花,但是这次的花瓣长度大于2.45厘米。你必须移动到根节点的右侧子节点(深度1,右),该节点不是叶节点,所以它提出另一个问题:花瓣宽度是否小于1.75厘米?如果是,那这朵花最有可能是Versicolor鸢尾花(深度2,左);如果不是,那就可能是Virginica鸢尾花(深度2,右)。就是这么简单。

2、训练完成后,使用决策树对测试集数据进行分类:

      决策树除了可以输出实例所属的类别k外,同样可以估算某个实例属于特定类别k的概率:首先,跟随决策树找到该实例的叶节点,然后返回该节点中类别k的训练实例占比。

例如,假设你发现一朵花,其花瓣长5厘米,宽1.5厘米。相应的叶节点为深度2左侧节点,因此决策树输出如下概率:Setosa鸢尾花,0%(0/54);Versicolor鸢尾花,90.7%(49/54);Virginica鸢尾花,9.3%(5/54)。当然,如果你要求它预测类别,那么它应该输出Versicolor鸢尾花(类别1),因为它的概率最高。

tree_clf.predict_proba([[5, 1.5]])
out:array([[0.        , 0.90740741, 0.09259259]])

tree_clf.predict([[5, 1.5]])
out:array([1])

       下图显示了决策树的决策边界。加粗直线表示根节点(深度0)的决策边界:花瓣长度=2.45厘米。因为左侧区域是纯的(只有Setosa鸢尾花),所以它不可再分。但是右侧区域是不纯的,所以深度1右侧的节点在花瓣宽度=1.75厘米处(虚线所示)再次分裂。因为这里最大深度max_depth设置为2,所以决策树在此停止。但是如果你将max_depth设置为3,那么两个深度为2的节点将各自再产生一条决策边界(点线所示)。

说明:决策树是非常直观的,它们的决策也很容易解释,这类模型通常被称为白盒模型。与之相反的,我们稍后将会看到,随机
森林或是神经网络被认为是一种黑盒模型。它们能做出很棒的预测,你也可以轻松检查它们在做出预测时执行的计算,然而,通常很难解释清楚它们为什么做出这样的预测。

CART训练算法

1、成本函数

      Scikit-Learn使用的是分类与回归树(Classification  And Regression  Tree,简称CART)算法来训练决策树。

     首先,使用单个特征k和阈值t_{k}(例如,花瓣长度≤2.45厘米)将训练集分成两个子集。k和阈值t_{k}怎么选择?答案是产生出最纯子集(受其大小加权)的k和t_{k}就是经算法搜索确定的(t,t_{k})。算法尝试最小化的成本函数为:

              

                 G_{i}=1-\sum ^{n}_{k=1}p_{i,k}^{2}

其中:p_{i,k}是第i个节点上,类别为k的训练实例占比。

       一旦成功将训练集一分为二,它将使用相同的逻辑,继续分裂子集,然后是子集的子集,依次循环递进。直到抵达最大深度(由max_depth控制),或是再也找不到能够降低不纯度的分裂,它才会停止。还有一些超参数可以用来控制附加的停止条件(min_samples_split、min_samples_leaf、min_weight_fraction_leaf及max_leaf_nodes)。

        CART是一种贪婪算法:从顶层开始搜索最优分裂,然后每层重复这个过程。几层分裂之后,它并不会检视这个分裂
的不纯度是否为可能的最低值。贪婪算法通常会产生一个相当不错的解,但是不能保证是最优解
         而寻找最优树是一个已知的NP完全问题:需要的时间是O(exp(m)),所以即使是很小的训练集,也相当棘手。

2、计算复杂度

      进行预测需要从根到叶遍历决策树。通常来说,决策树大致平衡,因此遍历决策树需要经历大约O(log_{2}(m))个节点。而每个节点只需要检查一个特征值,所以总体预测复杂度也只是{\color{Red}O(log_{2}(m)) },与特征数量无关。如此,即便是处理大型数据集,预测也很快。
      但是,训练时在每一个节点,算法都需要在所有样本上比较所有特征(如果设置了max_features会少一些)。这导致训练的复杂度为{\color{Red}O(n*mlog_{2}(m)) }对于小型训练集(几千个实例以内),Scikit-Learn可以通过对数据预处理(设置presort=True)来加快训练,但是对于较大训练集而言,可能会减慢训练的速度

3、基尼不纯度和信息熵

     默认使用的是基尼不纯度来进行测量,但是,你可以将超参数criterion设置为"entropy"来选择信息熵作为不纯度的测量方式。熵是一种分子混乱程度的度量:如果分子保持静止和良序,则熵接近于零。在机器学习中,它也经常被用作一种不纯度的测量方式:如果数据集中仅包含一个类别的实例,其熵为零。下式显示了第i个节点的熵值的计算方式。

                                        

例如,上图中深度2左侧节点的熵值:

                                     

     大多数情况下,二者并没有什么大的不同,产生的树都很相似。基尼不纯度的计算速度略微快一些,所以它是个不错的默认选择。它们的不同在于,基尼不纯度倾向于从树枝中分裂出最常见的类别,而信息熵则倾向于生产更平衡的树。

正则化超参数

       决策树极少对训练数据做出假设(线性模型假设数据是线性)。如果不加以限制,树的结构将跟随训练集变化,严密拟合,并且很可能过度拟合。这种模型通常被称为非参数模型。相应的参数模型,比如线性模型,则有预先设定好的一部分参数,因此其自由度受限,从而降低了过度拟合的风险(但是增加了拟合不足的风险)。
       为避免过度拟合,需要在训练过程中降低决策树的自由度。这个过程被称为正则化。正则化超参数的选择取决于你所使用的模型,但是通常来说,至少可以限制决策树的最大深度,由超参数max_depth控制(默认值为None,意味着无限制)。减小max_depth可使模型正则化,从而降低过度拟合的风险。
      DecisionTreeClassifier类还有一些其他的参数,同样可以限制决策树的形状:min_samples_split(分裂前节点必须有的最小样本数),min_samples_leaf(叶节点必须有的最小样本数量),min_weight_fraction_leaf(跟min_samples_leaf一样,但表现为加权实例总数的占比),max_leaf_nodes(最大叶节点数量),以及max_features(分裂每个节点评估的最大特征数量)。增大超参数min_*或是减小max_*将使模型正则化。

      还可以先不加约束地训练模型,然后再对不必要的节点进行剪枝(删除)。如果一个节点的子节点全部为叶节点,则该节点可被认为不必要。
     下图显示了在卫星数据集(见第5章介绍)上训练的两个决策树。左图使用默认参数(即无约束)来训练决策树,右图的决策树应用min_samples_leaf=4进行训练。很明显,左图模型过度拟合,右图的泛化效果更佳。

   

决策树的限制

1、对训练集的旋转非常敏感

      决策树很容易理解和解释,使用简单,功能全面并且十分强大。但是,它们确实也有一些限制。首先,你可能已经注意到,决策树的决策边界都与轴线垂直,这导致它们对训练集的旋转非常敏感。例如,下图显示了一个简单的线性可分离数据集:左图里,决策树可以很轻松分裂;而到了右边,数据集旋转45°后,决策边界产生了不必要的卷曲。虽然两个模型都看似完美拟合训练集,但是右侧模型很可能泛化不佳。解决这种问题的方法之一是使用PCA让训练数据定位在一个更好的方向上。

 2、对野值点敏感

     决策树的主要问题是它们对训练数据中的小变化非常敏感。我们以上面的决策树为例,如果你从鸢尾花数据集中移除花瓣最宽的Versicolor鸢尾花(花瓣长4.8厘米,宽1.8厘米),然后重新训练一个决策树,你可能得到下图所示的模型。这跟之前的决策树看起来截然不同。事实上,由于Scikit-Learn所使用的算法是随机的,即使是在相同的训练数据上,你也可能得到完全不同的模型(除非你对超参数random_state进行设置)。

#X有两列,下式查找一个样本点:属于y=1类;在该类中找到最大的Petal Width对应的样本点
X[(X[:, 1]==X[:, 1][y==1].max()) & (y==1)] # widest Iris-Versicolor flower

out:array([[4.8, 1.8]])

# 删除了一个野点,再进行训练
not_widest_versicolor = (X[:, 1]!=1.8) | (y==2)
X_tweaked = X[not_widest_versicolor]
y_tweaked = y[not_widest_versicolor]

tree_clf_tweaked = DecisionTreeClassifier(max_depth=2, random_state=40)
tree_clf_tweaked.fit(X_tweaked, y_tweaked)

 

 回归

决策树也可以执行回归任务。用DecisionTreeRegressor来构建一个回归树,在一个带噪声的二次数据集上进行训练

结果树如图所示

                

      跟之前建立的分类树很相似。主要差别在于,每个节点上不再是预测一个类别而是预测一个值。这个预测值其实就是与这个叶节点关联的110个实例的平均目标值例如,如果你想要对一个x1 =0.6的新实例进行预测,那么从根节点开始遍历,最后到达预测value=0.1106的叶节点。在这110个实例上,预测产生的均方误差(MSE)等于0.0151。

      下图左侧显示了该模型的预测,其中max_depth=2。如果设置max_depth=3,将得到如右图所示的预测。注意看,每个区域的预测值永远等于该区域内实例的目标平均值。算法分裂每个区域的方法,就是使最多的训练实例尽可能接近这个预测值。

      与分类任务一样,决策树在处理回归任务时也很容易过度拟合。如果没有任何正则化(即使用默认超参数),你将得到如图左侧所示的预测结果,这显然对训练集严重过度拟合。只需要设置min_samples_leaf=10,就能得到一个看起来合理得多的模型,如右图所示。

 

回归算法成本函数

      CART算法的工作原理跟前面介绍的大致相同,唯一不同在于,它分裂训练集的方式不是最小化不纯度,而是最小化MSE。下式显示了算法尝试最小化的成本函数

                       

  其中:                 

GitHub源码:https://github.com/liuzheCSDN/Scikit-Learn/blob/master/6_DecisionTree.ipynb

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值