《统计学习方法》 第五章 决策树及sklearn包中决策树算法的使用

本文内容参考李航老师的《统计学习方法》及其配套课件

python实现原文代码作者:https://github.com/wzyonggege/statistical-learning-method

sklearn包中决策树算法的使用资料链接:https://scikit-learn.org/dev/modules/tree.html

 

决策树的简介

        决策树Decision Trees是一种用于分类回归( classification and regression)的无监督学习方法。目标是创建一个模型,从数据特征中学习简单的决策规则来预测目标变量的值。

 

例如,在下面的示例中,决策树通过if-then-else的决策规则来学习数据从而估测到一个正弦曲线。树越深,决策规则越复杂,模型对数据的拟合效果就越好。

关于决策树的一些优点:

  • 便于理解和解释。树可以可视化。
  • 训练需要的数据少,其他的模型方法通常需要数据规范化 ,比如创建虚拟变量并且删除缺失值(注意,这个模型不支持缺失值)。
  • 训练模型的时间复杂度是参与训练数据点的对数值(训练决策树的数据点的数据量导致了)。
  • 使用白盒模型。如果某种给定的情况在模型中是可以观测的,那么就可以通过布尔逻辑解释这种情况。相比之下,在黑盒模型中(比如,人的神经网络)的结果就难以解释。
  • 可以用数值统计测试来验证模型。使解释验证该模型的可靠性成为可能。
  • 即使该模型假设的结果与真实模型所提供的数据有出入,但模型的效果仍旧很好。

决策树的一些缺点: 

  • 容易过拟合
  • 决策树可能不稳定,数据中微小的变化都可能导致生成完全不同的树。在集成中使用决策树可以缓解这个问题。
  • 学习最优决策树的问题通常是一个NP难问题。因此,实际的决策树学习算法是基于启发式算法。
  • 有些概念难以学习,决策树不容易表达。例如XOR,奇偶或者复用器的问题

 

决策树由结点(node) 和有向边(directed edge) 组成。 结点有两种类型: 内部结点(internal node) 和叶结点(leaf node)。内部结点表示一个特征或属性, 叶结点表示一个类。用决策树分类, 从根结点开始, 对实例的某一特征进行测试, 根据测试结果, 将实例分配到其子结点; 这时, 每一个子结点对应着该特征的一个取值。 如此递归地对实例进行测试并分配, 直至达到叶结点。 最后将实例分到叶结点的类中。

例如 上图就是一个决策过程生成的分类决策树,能想象一个女生要相亲,相当于通过年龄,长相,收入和是否是公务员对男孩分为两个类别:见和不见。假设这个女孩对男孩的要求是:30岁以下,长相中等以上并且是高收入者,或者中等以上收入的公务员,那么这个图表示女孩的决策逻辑。其中绿色结点表示判断条件,橙色结点表示决策结果,箭头表示在一个判断条件在不同情况下的决策路径,图中红色箭头表示了上面例子中女孩的决策过程。

 

决策树的构造

训练过程中构建这棵决策树的时候要怎么做呢?就是一个一个特征属性依次比较过去然后建立分支吗?不是的,我们需要挑选最有代表性的特征。特征选择在于选取对训练数据具有分类能力的特征。 这样可以提高决策树学习的效率。在构建决策树的过程中,最重要的就是怎么选取合适的特征来构建它。如果选取不合理,可能会造成产生的决策树过于庞大,提升程序的复杂度,此外也会造成决策树的泛化性能降低。生成决策树的算法通常有ID3、C4.5、CART。

信息增益

什么是信息的不确定性?就是信息熵。我们给出信息熵的定义:

在熵H(P)越大时,表示随机变量的不确定性越大。而熵越大,信息就越混乱,P(x)几率就越小。 

在决策树根节点的最初,我们先假设信息熵为1,表示我们的一无所知。到叶节点时假设信息熵为0,表示非常确信。那么使用决策树决策的过程就是我们不断减少信息熵的过程,直到它降为0。我们的目标是希望信息熵能下降得快一点。这就涉及到决策树的构建了,我们该怎么构建才能使得这棵决策树的信息熵在判断分支中下降得最快呢?这就是信息增益。

接下来给出信息增益的算法:

 

sklearn包中决策树算法的使用----分类 

与其他分类器一样,  DecisionTreeClassifier将两个数组作为输入:一个数组X,用[n_samples, n_features]存放训练样本;Y数组用[n_samples]来存放训练样本的类标签。

#导入sklearn包
>>> from sklearn import tree
>>> X = [[0, 0], [1, 1]]
>>> Y = [0, 1]
>>> clf = tree.DecisionTreeClassifier()
>>> clf = clf.fit(X, Y)

接下来,模型可以预测样本的类别。

>>> clf.predict([[2., 2.]])
array([1])

或者,可以预测每个类的概率,这个概率是叶子中同类训练样本的比例.predict_proba返回的是一个 n 行 k 列的数组, 第 i 行 第 j 列上的数值是模型预测 第 i 个预测样本为某个标签的概率,并且每一行的概率和为1。

>>> clf.predict_proba([[2., 2.]])
array([[0., 1.]])

所以结果表示预测[2.,2.]的标签是0的概率是0,是1的概率是1。

 DecisionTreeClassifier既支持二分类(其标签为[-1,1]),也支持多分类([0, …, K-1])。

利用Iris数据集,我们可以构建如下树:

>>> from sklearn.datasets import load_iris
>>> from sklearn import tree
>>> X, y = load_iris(return_X_y=True)
>>> clf = tree.DecisionTreeClassifier()
>>> clf = clf.fit(X, y)

一旦经过训练,可以用plot_tree 函数绘制树,也可以通过graphviz将树可视化。首先要安装一下这个包,如果用conda管理包可以用指令 conda install python-graphviz安装,我是先用系统安装了一下再用python安装。指令:brew install graphviz  // pip3 install graphviz

>>> import graphviz 
>>> dot_data = tree.export_graphviz(clf, out_file=None) 
>>> graph = graphviz.Source(dot_data) 
>>> graph.render("iris")

这样就已经生成一个pdf文件

 export_graphviz也支持各种美化图形。加入各种参数

dot_data = tree.export_graphviz(clf, out_file=None, 
                        feature_names=iris.feature_names,  
                        class_names=iris.target_names,  
                        filled=True, rounded=True)

graph=graphviz.Source(dot_data)
graph.render("iris")

接下来的示例用的是iris数据集。Iris 鸢尾花数据集是一个经典数据集,在统计学习和机器学习领域都经常被用作示例。数据集内包含 3 类(Iris Setosa,Iris Versicolour,Iris Virginica)共 150 条记录,每类各 50 个数据,每条记录都有 4 项特征:花萼长度、花萼宽度、花瓣长度、花瓣宽度,可以通过这4个特征预测鸢尾花卉属于哪一品种。

基于iris数据集绘制决策树

print(__doc__)

import numpy as np
import matplotlib.pyplot as plt

from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier, plot_tree

# Parameters
n_classes = 3
plot_colors = "ryb"
plot_step = 0.02

# Load data
iris = load_iris()

for pairidx, pair in enumerate([[0, 1], [0, 2], [0, 3],
                                [1, 2], [1, 3], [2, 3]]):
    # We only take the two corresponding features
    #从四列数据中选取两个特征进行训练
    X = iris.data[:, pair]
    y = iris.target

    # Train
    clf = DecisionTreeClassifier().fit(X, y)

    # Plot the decision boundary
    plt.subplot(2, 3, pairidx + 1)
    #subplot直接指定划分方式和位置进行绘图,2行3列排列图片
    
    #绘制决策边界,选择最大值,最小值
    x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
    y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1

    # numpy.meshgrid()——生成网格点坐标矩阵。numpy.arange()分割数
    xx, yy = np.meshgrid(np.arange(x_min, x_max, plot_step),
                         np.arange(y_min, y_max, plot_step))
    # tight_layout() 进行自动控制图像布局,通过参数pad, w_pad, h_pad设置布局细节
    plt.tight_layout(h_pad=0.5, w_pad=0.5, pad=2.5)

    
    # 按照第一个循环,把第一列花萼长度数据按h取等分,作为行,然后复制多行,得到xx网格矩阵
    #把第二列的花萼宽度数据按h取等分,作为列,复制多列,得到网格矩阵
    #np.c_是按列连接两个矩阵,就是把两矩阵左右相加,要求行数相等,类似于pandas中的merge()
    Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
    Z = Z.reshape(xx.shape)

    #绘制等高线的,contour和contourf都是画三维等高线图的
    #不同点在于contour() 是绘制轮廓线,contourf()会填充轮廓。
    #matplotlib.cm是色彩映射函数。 
    cs = plt.contourf(xx, yy, Z, cmap=plt.cm.RdYlBu)
       
    
    #横纵坐标label特征名称
    plt.xlabel(iris.feature_names[pair[0]])
    plt.ylabel(iris.feature_names[pair[1]])


    # Plot the training points 绘制每个类别的鸢尾花数据的散点图
    for i, color in zip(range(n_classes), plot_colors):
        # 这里的numpy.where()只有一个参数,返回条件为True的索引
        #所以这里会依次返回每种鸢尾花的样本索引。
        idx = np.where(y == i)
        #取出样本的第0列,第1列
        plt.scatter(X[idx, 0], X[idx, 1], c=color, label=iris.target_names[i],
                    cmap=plt.cm.RdYlBu, edgecolor='black', s=15)

plt.suptitle("Decision surface of a decision tree using paired features")
plt.legend(loc='lower right', borderpad=0, handletextpad=0)
plt.axis("tight")

plt.figure()
clf = DecisionTreeClassifier().fit(iris.data, iris.target)
plot_tree(clf, filled=True)
plt.show()

得到两个图 

 

上述代码中其中,iris.data数据如下

 此时X= iris.data[:,pair],第一个循环中取iris.data数据中的第0列和第1列即iris.data[: , [0,1] ]

代码中numpy.where(condition[,x,y])

参数:

condition : 数组,bool值

如果为True, 则产生 x, 否则产生  y.

x, y : array_like, 可选

x与y的shape要相同,当condition中的值是true时返回x对应位置的值,false是返回y的

返回值:

out : ndarray 或ndarray 原组

①如果参数有condition,x和y,它们三个参数的shape是相同的。那么,当condition中的值是true时返回x对应位置的值,false是返回y的。

②如果参数只有condition的话,返回值是condition中元素值为true的位置索引,切是以元组形式返回,元组的元素是ndarray数组,表示位置的索引

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值