专栏首页人人都是极客Peter教你谈情说AI | 09决策树(下)—既能回归又能分类的模型

Peter教你谈情说AI | 09决策树(下)—既能回归又能分类的模型

Hello Kitty到底是猫还是女孩?让决策树告诉我们真伪。

特征选取

我们提取七个特征,用来判断一个形象,是人是猫。这七个特征包括:有否蝴蝶结;是否穿衣服;是否高过5个苹果;是否有胡子;是否圆脸;是否有猫耳朵;是否两脚走路。

用一个表格来表现这七个特征则,如下图所示(第一列为 Label,第二至八列为7个特征,每个特征只有两个取值,Yes 或者 No):

Table-1

用 ID3 算法构造分类树

本例中,我们选用最简单的 ID3 算法,代入数据进行计算。

(1)根据信息熵的概念,我们先来计算 Entropy(S)。因为总共只有两个类别:人和猫,因此 n==2。

(2)然后我们再分别计算各个特征的:

因为无论哪个特征,都只有两个特征值:Yes 或者 No,因此value(T)总共只有两个取值。

下面以“Has a bow”为例来示意其计算过程。

依次计算其他几项,得出如下结果:

(3)进一步计算,得出 InfoGain(Has cat ears) 最大,因此“Has cat ears”是第一个分裂节点。

而从这一特征对应的类别也可以看出,所有特征值为 No 的都一定是 Girl;特征值为 Yes,可能是 Girl 也可能是 Cat,那么第一次分裂,我们得出如下结果:

现在“Has cat ears”已经成为了分裂点,则下一步将其排除,用剩下的6个 Feature 继续分裂成树:

Table-2

Table-2 为第二次分裂所使用的训练数据,相对于 Table-1,“Has cat ears”列,和前7行对应“Has cat ears”为 No 的数据都已经被移除,剩下部分用于第二次分裂。

如此反复迭代,最后使得7个特征都成为分裂点。

需要注意的是,如果某个特征被选为当前轮的分裂点,但是它在现存数据中只有一个值,另一个值对应的记录为空,则这个时候针对不存在的特征值,将它标记为该特征在所有训练数据中所占比例最大的类型。

对本例而言,当我们将“Wear Clothes”作为分裂点时,会发现该特征只剩下了一个选项——Yes(如下 Table-3 所示)。此时怎么给“Wear Clothes”为 No 的分支做标记呢?

Table-3

这时就要看在 Table-1 中,“Wear Clothes”为 No 的记录中是 Girl 多还是 Cat 多。一目了然,在 Table-1 中这两种记录数量为 0:6,因此“Wear Clothes”为 No 的分支直接标志成 Cat。

根据上述方法,最终我们构建出了如下决策树:

决策树构建过程,如下代码所示:

    DecisionTree induceTree(training_set, features) {
        If(training_set中所有的输入项都被标记为同一个label){
          return 一个标志位该label的叶子节点;
        } else if(features为空) {
          # 默认标记为在所有training_set中所占比例最大的label 
          return 一个标记为默认label的叶子节点;  
        } else {
          选取一个feature,F;
          以F为根节点创建一棵树currentTree;
          从Features中删除F;
          foreach(value V of F) {                                
              将training_set中feature F的取值为V的元素全部提取出来,组成partition_v;
              branch_v= induceTree(partition_V, features);
              将branch_v添加为根节点的子树,根节点到branch_v的路径为F的V值;
          }
              returncurrentTree;
        }
    }

后剪枝优化决策树

决策树剪枝

剪枝是优化决策树的常用手段。剪枝方法大致可以分为两类:

  1. 先剪枝(局部剪枝):在构造过程中,当某个节点满足剪枝条件,则直接停止此分支的构造。
  2. 后剪枝(全局剪枝):先构造完成完整的决策树,再通过某些条件遍历树进行剪枝。

后剪枝优化 Hello Kitty 树

现在,决策树已经构造完成,所以我们采用后剪枝法,对上面决策树进行修剪。

如图中显示,最后两个分裂点“Has round face”和“Has a bow”存在并无意义——想想也是啊,无论人猫,都有可能是圆脸,也都可以戴蝴蝶结啊。

以我们遍历所有节点,将没有区分作用的节点删除。完成后,我们的决策树变成了下面这样:

代码实现

下面的代码就是用 numpy 和 sklearn 来实现例子中的训练分类树来判断 Hello Kitty 种族所对应的程序。

    from sklearn import tree
    from sklearn.model_selection im
    port train_test_split
    import numpy as np

    #9个女孩和8只猫的数据,对应7个feature,yes取值为1,no为0
    features = np.array([
        [1, 1, 0, 0, 1, 0, 1],
        [1, 1, 1, 0, 0, 0, 1],
        [0, 1, 0, 0, 0, 0, 1],
        [1, 1, 0, 0, 1, 0, 1],
        [0, 1, 0, 0, 1, 0, 0],
        [0, 1, 0, 0, 1, 0, 1],
        [1, 1, 0, 0, 1, 0, 0],
        [0, 1, 0, 0, 1, 0, 1],
        [0, 1, 0, 1, 1, 1, 1],
        [1, 0, 1, 1, 1, 1, 0],
        [0, 0, 0, 1, 1, 1, 0],
        [1, 0, 1, 1, 1, 1, 0],
        [0, 0, 0, 1, 1, 1, 0],
        [1, 0, 0, 1, 1, 1, 0],
        [0, 0, 1, 0, 1, 1, 0],
        [1, 1, 1, 1, 1, 1, 0],
        [1, 0, 1, 1, 1, 1, 0]
    ])

    #1 表示是女孩,0表示是猫  
    labels = np.array([
        [1],
        [1],
        [1],
        [1],
        [1],
        [1],
        [1],
        [1],
        [1],
        [0],
        [0],
        [0],
        [0],
        [0],
        [0],
        [0],
        [0],
    ])

    # 从数据集中取20%作为测试集,其他作为训练集
    X_train, X_test, y_train, y_test = train_test_split(
        features,
        labels,
        test_size=0.2,
        random_state=0,
    )

    # 训练分类树模型
    clf = tree.DecisionTreeClassifier()
    clf.fit(X=X_train, y=y_train)

    # 测试
    print(clf.predict(X_test))
    # 对比测试结果和预期结果
    print(clf.score(X=X_test, y=y_test))

    # 预测HelloKitty
    HelloKitty = np.array([[1,1,1,1,1,1,1]])
    print(clf.predict(HelloKitty))

最后输出为:

[1 1 0 0]

0.75

[0]

本文分享自微信公众号 - 人人都是极客(rrgeek)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-11-06

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 操作系统产生死锁的原因和处理策略

    当进程需要以独占的方式访问资源时,可能会发生死锁(Deadlock)。死锁是指两个或以上进程因竞争临界资源而造成的一种僵局,即一个进程等待一个已经被占用且永不释...

    刘盼
  • Peter教你谈情说AI | 05用梯度下降法求线性回归模型

    监督学习指的是人类给机器一大堆标示(label)过的数据,通常指机器通过学习一系列(, )数据,X代表输入数据(特征Feature),Y代表输出数据,然后自我推...

    刘盼
  • 进程、线程之间的爱恨纠葛...

    当一个程序开始执行后,在开始执行到执行完毕退出这段时间内,它在内存中的部分就叫称作一个进程。

    刘盼
  • Python unittest自动化01

    什么是单元测试?单元测试负责最小的软件设计单元进行验证,unittest框架(原名PyUnit框架)为python自带的单元测试框架。

    wencheng
  • Linux下查看压缩文件内容的 10 种方法

    通常来说,我们查看归档或压缩文件的内容,需要先进行解压缩,然后再查看,比较麻烦。今天给大家介绍 10 不同方法,能够让你轻松地在未解压缩的情况下查看归档或压缩文...

    心莱科技雪雁
  • R语言数据分布检验的小例子

    今天在B站看了毕导的《我给自己发了2亿个红包,才发现先抢和后抢的差距这么大!》的视频,非常有意思,大家感兴趣也可以到B站观看。

    用户7010445
  • 懒人经济”新浪潮 【图观大数据16期】

    《“懒人经济”新机会》46页深度报告!历时一月时间,通过两轮调查和多方面深度采写,先后共有32011名用户参于到调查中,我们希望可以找到关于O2O创业的真正机会...

    小莹莹
  • “懒人经济”新浪潮

    《“懒人经济”新机会》46页深度报告!历时一月时间,通过两轮调查和多方面深度采写,先后共有32011名用户参于到调查中,我们希望可以找到关于O2O创业的真正机会...

    腾讯大讲堂
  • maven打包子模块中的class文件

    通常在项目中都会使用maven进行多模块管理,默认被依赖的模块都会以jar包形式被引用。 然而在J2EE项目中,当使用了Spring的自动扫描配置时,jar包形...

    2Simple
  • Maven打包跳过测试

    - DskipTests,不执行测试用例,但编译测试用例类生成相应的class文件至target/test-classes下

    三分恶

扫码关注云+社区

领取腾讯云代金券