美文网首页人工智能工程师
决策树(Decision Tree)算法

决策树(Decision Tree)算法

作者: longsan0918 | 来源:发表于2018-12-21 15:19 被阅读8次

    1 理论部分

    需要弄清楚几个概念
    信息熵,决策树,决策树优化, 剪枝 ,决策树可视化

    1 信息熵(Entropy 单位bit)

    每条消息包含的信息的平均量(信息熵越大 信息量越大 系统越无序,具有更高的不确定性, 越混乱)
    信息量: I(xi)=−logp(xi) (负号: 概率越小 logp(xi)越小 -logp(xi)越大)

    信息熵其实是一个随机变量信息量的数学期望


    image.png

    2 决策树

    决策树是一种树形结构,其中每个内部节点表示一个属性上的测试,每个分支代表一个测试输出,每个叶节点代表一种类别。

    3 决策树优化

    决策树模型生成后会存在欠拟合和过拟合的问题。如何解决这些问题就是决策树优化需要考虑的。

    4 剪枝

    防止决策树过拟合的过程

    5 决策树可视化

    导入一些模块,将树形结构展示给用户

    • 决策树的直观理解
      根据“年收入” “房产” “婚姻情况” 判断一个人是否有偿还能力
      决策树类似代码中的if else else if .......


      2D2B7764-0DE7-4890-B3DB-F4737D2E5690.png
    • 比特化


      IMG_3046.JPG

    变量所占比特位计算方式


    image.png

    信息熵 = 比特化随机变量X占用比特位的数学期望

    • 条件熵
      H(Y|X) 给定条件X 随机变量Y的信息熵
      H(Y|X) = H(X,Y)-H(X)

    决策树构建过程

    从根节点开始 测试待分类项对应的特征属性 并按照其值选择输出分支,直到叶子节点,将叶子节点存放的类别作为决策结果

    构建步骤:
    1 将所有的特征看成一个一个的节点
    2 遍历当前所有的特征的每一种分割方式 找到最好的分割点,将数据划分为不同的子节点(关键是找到最好的分割点)
    3 循环遍历 最终得到每个子节点足够纯

    决策树特征属性类型
    离散值 不要求生成二叉树 一个属性就是一个分支
    离散值 生成二叉树 按"属于此子集"和“不属于此子集”划分
    连续值 确定一个分割点 split_point 按照“>split_point”和"<=split_point"分为两个分支

    决策树 量化纯度
    Gini系数 熵(Entrory) 错误率
    越大 越不纯 越小越纯

    AC805900-793C-419B-A8CF-634284F9DF82.png image.png

    信息增益度

    当计算出各个特征属性的量化纯度值后,使用信息增益度来选择出当前数据集的分割特征属性。如果信息增益度值越大,表示在该特征属性上会损失的纯度越大,那么该属性越应该在决策树的上层。计算公式如下: image.png
    Gain为A在特征对训练数据集D的信息增益,它为集合D的经验熵H(D)与特征A给定条件下D的经验条件熵H(D|A)之差。

    Gain= 蓝色区域 = H(D) - H(D|A)


    image.png
    如果信息增益度值越大,表示在该特征属性上会损失的纯度越大,那么该属性越应该在决策树的上层。
    决策树算法停止条件

    1 方式一 当每个子节点只有一种类型的时候停止构建(会树的节点过多 导致过拟合)
    2 方式二 当前节点的样本数小于某个阈值 同时迭代次数到达某个特定的值时 停止构建
    1 决策树最大深度 max_depth
    2 min_samples_split 最小样本数
    3 min_samples_leaf 最少叶子节点数
    4 max_leaf_nodes 最大叶子节点数
    5 min_impurity_split 节点划分不纯度

    分两类: 分类树和回归树 分类树用来分类标签值 回归树用来预测连续值
    常见算法 ID3,C4.5,CART

    决策树算法效果评估

    1 跟一般的分类算法一样 采用混淆矩阵来进行计算准确率,召回率,精确率
    2 叶子节点的纯度值总和 值越小 效果越好

    BCCDA108-C104-4AF4-9BD9-924028958EB5.png

    重点回顾:
    1、Gain为A在特征对训练数据集D的信息增益,它为集合D的经验熵H(D)与特征A给定条件下D的经验条件熵H(D|A)之差。
    2、不能将所有叶子节点的信息熵单纯的求和,还得乘上一个权重值,权重值=当前叶子节点的样本个数/总的样本个数。比如说上图中有房产/总样本 = 0.4 无房产/总样本 = 0.6


    image.png

    思考:
    在决策树中的每一个节点都能够表示一个系统,都能够计算其信息熵(系统稳定程度)。
    如果将这些信息熵单纯的求和结果会不太理想。比如有100个节点,前99个节点中有很多数据,但是第100个节点只有1条数据。按理说,这第100个节点对于整个系统的不稳定性起了非常小的作用。如果还有一个节点,这个节点里有大量的数据,且结果都为分类0,那么可以认为这个节点的划分比较成功,在计算整个决策树总损失的算法中,该节点要占用一个较大的比例。
    所以:不能将所有叶子节点的信息熵单纯的求和,还得乘上一个权重值,权重值=当前叶子节点的样本个数/总的样本个数。


    A893A364-28A4-4AFA-94F9-FD6F6174978C.png IMG_3054.JPG C2A26E5A-2A7B-41E9-A447-A7326943FE5D.png

    决策树常见算法

    IMG_3056.JPG 00A63FA8-79BA-4E2E-AAAE-37D3166A42A6.png

    2 代码实现

    # -*- coding: utf-8 -*-
    # @Time    : 2018/12/20 下午7:11
    # @Author  : scl
    # @Email   : 1163820757@qq.com
    # @File    : 决策树莺尾花(全).py
    # @Software: PyCharm
    
    '''
     决策树案例 莺尾花数据分类
    '''
    
    import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt
    import matplotlib as mpl
    import warnings
    
    from sklearn.model_selection  import train_test_split #测试集和训练集
    from sklearn.preprocessing import MinMaxScaler #归一化处理库
    
    from sklearn.tree import DecisionTreeClassifier
    
    from sklearn.feature_selection import SelectKBest #特征选择
    from sklearn.feature_selection import chi2 #卡方统计量
    from sklearn.decomposition import PCA #主成分分析
    
    ## 设置属性防止中文乱码
    mpl.rcParams['font.sans-serif'] = [u'SimHei']
    mpl.rcParams['axes.unicode_minus'] = False
    warnings.filterwarnings('ignore', category=FutureWarning)
    
    
    path = './datas/iris.data'
    data = pd.read_csv(path, header = None)
    x = data[list(range(4))]
    # print(np.array(data[4]))
    y = pd.Categorical(data[4]).codes  #这个分类的分类代码
    # print(y)
    print("总样本数目:%d 特征属性数目%d"%(x.shape))
    
    x_train, x_test, y_train, y_test = train_test_split(x, y,train_size = 0.8,
                                                        test_size=0.2,random_state=14)
    ## 因为需要体现以下是分类模型,因为DecisionTreeClassifier是分类算法,要求y必须是int类型
    y_train = y_train.astype(np.int)
    y_test = y_test.astype(np.int)
    
    # 数据标准化
    ss = MinMaxScaler()
    x_train = ss.fit_transform(x_train)
    x_test = ss.fit_transform(x_test)
    
    # 特征选择
    ch2 = SelectKBest(chi2,k=3)
    x_train = ch2.fit_transform(x_train,y_train)
    x_test = ch2.transform(x_test)
    select_name_index = ch2.get_support(indices=True)
    print ("对类别判断影响最大的三个特征属性分布是:",ch2.get_support(indices=False))
    print(select_name_index)
    
    # 降维处理
    pca = PCA(n_components=2)
    x_train = pca.fit_transform(x_train,y_train)
    x_test = pca.transform(x_test)
    
    
    
    
    # 模型加载
    model = DecisionTreeClassifier(criterion='entropy',max_depth=20,random_state=0)
    model.fit(x_train,y_train)
    
    predict_hat = model.predict(x_test)
    
    print("预测值%s"%(predict_hat))
    print("训练集上的准确率%s"%(model.score(x_train,y_train)))
    print("测试集准确率%s"%(model.score(x_test,y_test)))
    print("特征的权重%s"%(model.feature_importances_)) #重要性权重,值越大表示该特征对于目标属性y的影响越大
    
    
    # 画图 横竖轴
    # 横轴采样范围 x1_min x1_max
    x1_min = np.min((x_train.T[0].min(),x_test.T[0].min()))
    x1_max = np.max((x_test.T[0].max(),x_train.T[0].max()))
    
    x2_min = np.min((x_train.T[1].min(),x_test.T[1].min()))
    x2_max = np.max((x_train.T[1].max(),x_test.T[1].max()))
    
    print("横轴采样范围 [%s %s]"%(x1_min,x1_max))
    print("纵轴采样范围 [%s %s]"%(x2_min,x2_max))
    
    N = 100 #采样点
    t1 = np.linspace(x1_min,x1_max,N)
    t2 = np.linspace(x2_min,x2_max,N)
    x1, x2 = np.meshgrid(t1,t2) # 生成网格采样点
    x_show = np.dstack((x1.flat,x2.flat))[0] #测试点
    
    y_show_hat = model.predict(x_show) #预测值
    
    y_show_hat = y_show_hat.reshape(x1.shape)  #使之与输入的形状相同
    
    print(y_show_hat.shape)
    print(y_show_hat[0])
    print(y_show_hat[1])
    
    
    # 画图 画样本点
    plt_light = mpl.colors.ListedColormap(['#A0FFA0', '#FFA0A0', '#A0A0FF'])
    plt_dark = mpl.colors.ListedColormap(['g', 'r', 'b'])
    
    plt.figure(facecolor='w')
    
    ## 画一个区域
    plt.pcolormesh(x1,x2,y_show_hat,cmap = plt_light)
    
    # 画测试数据的点信息
    plt.scatter(x_test.T[0], x_test.T[1], c=y_test.ravel(), edgecolors='k', s=150, zorder=10, cmap=plt_dark, marker='*')  # 测试数据
    # 画训练数据的点信息
    plt.scatter(x_train.T[0], x_train.T[1], c=y_train.ravel(), edgecolors='k', s=40, cmap=plt_dark)  # 全部数据
    plt.xlabel(u'特征属性x1', fontsize=15)
    plt.ylabel(u'特征属性x2', fontsize=15)
    plt.xlim(x1_min, x1_max)
    plt.ylim(x2_min, x2_max)
    plt.grid(True)
    plt.title(u'鸢尾花数据的决策树分类', fontsize=18)
    plt.show()
    
    #基于原始数据前3列比较一下决策树在不同深度的情况下错误率
    x_train4, x_test4, y_train4, y_test4 = train_test_split(x.iloc[:,:2],y,train_size=0.7,test_size=0.3,random_state=14)
    
    depths = np.arange(1,15)
    err_list = []
    for d in depths:
        clf = DecisionTreeClassifier(criterion='entropy',max_depth=d,min_samples_split=10)
        clf.fit(x_train4,y_train4)
    
        score = clf.score(x_test4,y_test4)
        err = 1- score
        err_list.append(err)
        print('树的深度%d 训练集上的正确率%.5f'%(d,clf.score(x_train4,y_train4)))
        print("树的深度%d 测试集合上正确率%.5f"%(d,score))
    
    plt.figure(facecolor='w')
    plt.plot(depths, err_list,'ro-',lw=3)
    plt.xlabel(u'决策树的深度',fontsize=16)
    plt.ylabel(u'错误率',fontsize=16)
    plt.grid(True)
    plt.title(u'树的深度导致过拟合(欠拟合)问题')
    plt.show()
    

    效果图


    决策树.png 决策树深度分析.png

    3 决策树可视化

    安装 graphviz服务
    1 ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
    2 brew install graphviz
    3 怎么使用
    新建pic.dot文件
    digraph pic {
    Hello -> World
    }
    打开终端 在pic.dot文件所在目录 dot pic.dot -T png -o pic.png

    pic.png

    brew install graphviz
    pip install pydotplus

    import pydotplus
    from sklearn import tree
    
    dot_data = tree.export_graphviz(model,out_file=None)
    graph = pydotplus.graph_from_dot_data(dot_data)
    # graph.write_png("0.png")
    graph.write_pdf("iris2.pdf")
    
    image.png

    相关文章

      网友评论

        本文标题:决策树(Decision Tree)算法

        本文链接:https://www.haomeiwen.com/subject/tpedkqtx.html