机器学习实战之决策树

决策树的算法可谓是贴近我们的生活,通过下面的案例,你就会发现我们每天都在有意无意的使用着决策树算法(好厉害的样子)。 小明同学每天早上都要去学校,可步行、乘公交和坐隔壁老王叔叔的车(皮一下很开心)。这时,小明就开始做决策了:首先看天气,不下雨时就选择步行去学校;下雨时就看隔壁老王叔叔是否有空,有空就乘老王的车去学校,没空就选择乘公交去学校。如图所示。

案例

决策树定义

通过上述案例,就可以对决策树下定义了:上图就是决策树(嗯。。。有点敷衍)。决策树由结点和有向边组成。结点有两种类型:内部节点和叶节点,内部节点表示一个特征或属性(天气,是否有空),叶节点表示一个类(步行、乘公交和坐隔壁老王叔叔的车)。

决策树算法原理

那怎么通过决策树算法来构造这棵树呢?(难道是上帝之手么?)上述案例较简单,我们现在提出一个很经典的案例,如图所示,我们首先到底是通过天气、湿度还是风级来进行决策了?这里就要提出熵和信息增益。

案例

首先,我们看什么是熵。简单来说,熵是描述事物的混乱程度的(也可以说是不确定性)。例如:中国足球进入世界杯,这个不确定性可能是0,所以熵可能就是0;6面的色子的不确定性比12面色子的要低,所以熵也会比其低。现在就来看熵的公式:H = -∑ni=1p(xi)log2p(xi) 那6面色子的熵:1/6*log21/6的6倍,也就是2.585 以此类推,那12面的熵就是:3.585 最后,我们计算下该案例的信息熵:不打球为5,打球为9,因此熵计算为:

-(5/14 * log(5/14,2) + 9/14 * log(9/14,2))
0.940
信息增益

到底先按哪个特征划分数据集呢?我们有个原则,就是将无序的数据变得有序,换句话说,就是让熵变小,变的越小越好。而信息增益就是划分数据集前后熵的变化,这里就是要让信息增益越大越好。 我们以天气为例,计算划分后的信息增益:

  • 晴天时:2/5打球,3/5不打球,熵为:
-(2/5 * log(2/5,2) + 3/5 * log(3/5,2))
0.971
  • 阴天熵:0
  • 雨天熵:0.971

天气 天气为晴天、阴天和雨天的概率为5/14,4/14和5/14,所以划分后的熵为:5/14 * 0.971+4/14 * 0+5/14 * 0.971得0.693,信息增益为0.940-0.693为0.247,同理可以求出其他特征的信息增益。 这里的天气信息增益最大,所以选择其为初始的划分依据。 选择完天气做为第一个划分依据后,能够正确分类的就结束划分,不能够正确分类的就继续算其余特征的信息增益,继续前面的操作,结果如图所示。

结果

伪代码

所以决策树是一个递归算法,伪代码如下:

def createBranch():
    检测数据集中的所有数据的分类标签是否相同:
        If so return 类标签
        Else:
            寻找划分数据集的最好特征(划分之后信息熵最小,也就是信息增益最大的特征)
            划分数据集
            创建分支节点
                for 每个划分的子集
                    调用函数 createBranch (创建分支的函数)并增加返回结果到分支节点中
            return 分支节点

决策树之海洋生物分类

问题描述与数据

数据为判断是否为鱼类,有两个特征:

  • 在水中是否生存
  • 是否有脚蹼

案例 这里需要我们自己手动构造数据:

def creatDataSet():
    dataSet = [
        [1, 1, 'yes'],
        [1, 1, 'yes'],
        [1, 0, 'no'],
        [0, 1, 'no'],
        [0, 1, 'no']
    ]
    labels = ['no surfacing', 'flippers']
    return dataSet, labels

这里的dataSet为数据,labels是两个特征的名称。

计算熵

这里我们定义一个计算数据集熵的函数:

from math import log

def calcshannon(dataSet):
    num = len(dataSet)
    labelCounts = {}
    for featVec in dataSet:
        currentLabel = featVec[-1]
        if currentLabel not in labelCounts.keys():
            labelCounts[currentLabel] = 0
        labelCounts[currentLabel] += 1
    shannon = 0.0
    for key in labelCounts:
        prob = float(labelCounts[key])/num
        shannon -= prob * log(prob, 2)
    return shannon

这个代码比较简单,就是对传入的数据,以最后一列(也就是分类label)求熵。

划分数据集

首先设置一个划分数据集的函数,参数为:待划分的数据,划分的特征和返回的特征值,该函数会在choose函数中被调用,用于计算最好的划分特征。

def splitDataSet(dataSet, axis, value):
    retDataSet = []
    for featVec in dataSet:
        if featVec[axis] == value:
            reduce = featVec[:axis]
            reduce.extend(featVec[axis+1:])
            retDataSet.append(reduce)
    return retDataSet
def choose(dataSet):
    numfeature = len(dataSet[0]) - 1
    baseEntropy = calcshannon(dataSet)
    bestinfogain = 0.0
    bestfeature = -1
    for i in range(numfeature):
        featlist = [example[i] for example in dataSet]
        vals = set(featlist)
        newEntropy = 0.0
        for value in vals:
            subDataSet = splitDataSet(dataSet, i, value)
            prob = len(subDataSet)/float(len(dataSet))
            newEntropy += prob*calcshannon(subDataSet)
        infoGain = baseEntropy - newEntropy
        if (infoGain > bestinfogain):
            bestinfogain = infoGain
            bestfeature = i
        return bestfeature
创建树

在所有特征使用完时,也没法对数据进行彻底的划分时,就需要使用多数表决来确定叶子节点的分类,代码如下,类似前文中KNN中的排序。

import operator
def majority(classList):
    classCount = {}
    for vote in classList:
        if vote not in classCount.keys():
            classCount[vote] = 0
        classCount[vote] += 1
    sortedcount = sorted(classCount.items(),  key=operator.itemgetter(1), reverse=True)
    return sortedcount[0][0]

最后就是创建树的代码:

def createTree(dataSet, labels):
    classList = [example[-1] for example in dataSet]
    if classList.count(classList[0]) == len(classList):
        return classList[0]
    if len(dataSet[0]) == 1:
        return majority(classList)
    bestFeat = choose(dataSet)
    bestFeatLabel = labels[bestFeat]
    myTree = {bestFeatLabel:{}}
    del (labels[bestFeat])
    Vals = [example[bestFeat] for example in dataSet]
    uvals = set(Vals)
    for value in uvals:
        sublabels = labels[:]
        myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value), sublabels)
    return myTree

这里有两个终止递归的条件:一是所有类别能正确的划分了,二是特征使用完成。

结果

算法优缺点

  • 优点:利于理解
  • 缺点:容易过拟合

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

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏专知

【论文推荐】最新七篇知识图谱相关论文—嵌入式知识、Zero-shot识别、知识图谱嵌入、网络库、变分推理、解释、弱监督

【导读】专知内容组整理了最近七篇知识图谱(Knowledge graphs)相关文章,为大家进行介绍,欢迎查看! 1.Learning over Knowled...

4648
来自专栏AI科技大本营的专栏

技能 | 只要五步,教你撸一个缩减版国际象棋AI

从国际象棋到中国围棋,人类与“机器”已经较上了劲。 看过那么多场对战,你是不是也想上手体验一把? 来来来,简单五步,手把手教你撸一个缩减版的国际象棋AI。 ...

2777
来自专栏小樱的经验随笔

遗传算法详解(LINGO及MatlabGA工具箱求解实现)

遗传算法 1.前言 遗传算法是一种基于生物界自然群体遗传进化机制的自适应全局优化概率搜索算法。它与传统算法不同,不依赖梯度信息,而是通过模拟自然进化过程来搜索最...

6266
来自专栏大数据挖掘DT机器学习

Python机器学习从原理到实践(1):决策树分类算法

一、决策树原理 决策树是用样本的属性作为结点,用属性的取值作为分支的树结构。 决策树的根结点是所有样本中信息量最大的属性。树的中间结点是该结点为根的子树所包含...

4028
来自专栏数据派THU

为你分享73篇论文解决深度强化学习的18个关键问题

来源:PaperWeekly 作者:王凌霄 本文共2434字,建议阅读5分钟。 本文为大家分享了73篇论文,介绍深度学习的方法策略以及关键问题分析。 这两天我阅...

2379
来自专栏Python中文社区

机器学习实战之决策树

决策树的算法可谓是贴近我们的生活,通过下面的案例,你就会发现我们每天都在有意无意的使用着决策树算法(好厉害的样子)。

982
来自专栏专知

【论文推荐】最新六篇机器翻译相关论文—综述、卷积Encoder-Decoder神经网络、字翻译、自编码器、神经短语、RNNs

【导读】专知内容组整理了最近六篇机器翻译(Machine Translation)相关文章,为大家进行介绍,欢迎查看! 1. Machine Translat...

4075
来自专栏CVer

论文精读 | LaneNet 端到端车道线检测的实例分割方法

关注CVer微信公众号的同学,应该知道CVer有个主题系列是“论文速递”,旨在分享计算机视觉相关领域最新的论文,每次推文近数篇论文,只是整理论文最精华的部分“摘...

2544
来自专栏IT派

HMM模型详解

最近一个赌场的老板发现生意不畅,于是派出手下去赌场张望。经探子回报,有位大叔在赌场中总能赢到钱,玩得一手好骰子,几乎是战无不胜。而且每次玩骰子的时候周围都有几个...

3514
来自专栏懒人开发

(2)James Stewart Calculus 5th Edition:Limits and Derivatives

712

扫码关注云+社区