3-3节 决策树|选择最好的数据集划分方式|机器学习实战-学习笔记

文章原创,最近更新:2018-08-13

本章节的主要内容是:
重点介绍项目案例1:判定鱼类和非鱼类选择最好的数据集划分方式的函数代码

1.决策树项目案例介绍:

项目案例1:

判定鱼类和非鱼类

项目概述:
  • 根据以下 2 个特征,将动物分成两类:鱼类和非鱼类。
  • 特征: 1. 不浮出水面是否可以生存 2. 是否有脚蹼
开发流程:
  • 收集数据:可以使用任何方法
  • 准备数据:树构造算法只适用于标称型数据,因此数值型数据必须离散化
  • 分析数据:可以使用任何方法,构造树完成之后,我们应该检查图形是否符合预期
  • 训练算法:构造树的数据结构
  • 测试算法:使用决策树执行分类
  • 使用算法:此步骤可以适用于任何监督学习算法,而使用决策树可以更好地理解数据的内在含义
数据集介绍

2.选择最好的数据集划分方式的函数代码

接下来我们将遍历整个数据集,循环计算香农熵和 splitDataSet()函数,找到最好的特征划分方式。熵计算将会告诉我们如何划分数据集是最好的数据组织方式.

打开文本编辑器,在 trees.py文件中输入下面的程序代码。

def chooseBestFeatTopSplit(dataSet):
    """chooseBestFeatureToSplit(选择最好的特征)

    Args:
        dataSet 数据集
    Returns:
        bestFeature 最优的特征列
    """
    # 求第一行有多少列的 Feature, 减去1,是因为最后一列是label列
    numFeatures = len(dataSet[0])-1
    # 计算没有经过划分的数据的香农熵
    baseEntropy = calcShannonEnt(dataSet) 
    # 最优的信息增益值
    bestInfoGain = 0.0
    #最优的Featurn编号
    bestFeature = -1
    for i in range(numFeatures): 
        # 创建唯一的分类标签列表,获取第i个的所有特征(信息元纵排列!)
        featList = [example[i] for example in dataSet]
        """
        print(featList)结果为
        [1, 1, 1, 0, 0]
        [1, 1, 0, 1, 1]
        """
        # 使用set集,排除featList中的重复标签,得到唯一分类的集合
        uniqueVals = set(featList)
        """
        print(uniqueVals)结果为
        {0, 1}
        {0, 1}
        """
        newEntropy = 0.0
         # 遍历当次uniqueVals中所有的标签value(这里是0,1)
        for value in uniqueVals: 
            # 对第i个数据划分数据集, 返回所有包含i的数据(已排除第i个特征)
            subDataSet = splitDataSet(dataSet, i, value)
            """
            print(subDataSet)结果为
            [[1, 'no'], [1, 'no']]
            [[1, 'yes'], [1, 'yes'], [0, 'no']]
            [[1, 'no']]
            [[1, 'yes'], [1, 'yes'], [0, 'no'], [0, 'no']]
            """        
            # 计算包含个i的数据占总数据的百分比
            prob = len(subDataSet)/float(len(dataSet))
            """
            print(prob)结果为
            0.4
            0.6
            0.2
            0.8
            """
            # 计算新的香农熵,不断进行迭代,这个计算过程仅在包含指定特征标签子集中进行
            newEntropy += prob * calcShannonEnt(subDataSet) 
            """
            print(calcShannonEnt(subDataSet))
            0.0
            0.9182958340544896
            0.0
            1.0
        
            print(newEntropy)结果为
            0.0
            0.5509775004326937
            0.0
            0.8
            """
            
            # 计算信息增益
            infoGain = baseEntropy - newEntropy
            # 如果信息增益大于最优增益,即新增益newEntropy越小,信息增益越大,分类也就更优(分类越简单越好)
            """
            print(infoGain)结果为
            0.4199730940219749
            0.17095059445466854
            """
            
            if (infoGain > bestInfoGain): 
                # 更新信息增益 
                bestInfoGain = infoGain
                # 确定最优增益的特征索引
                bestFeature = i 
                # 更新信息增益
        # 返回最优增益的索引
        return bestFeature 

测试代码及其 结果如下:

import trees
myDat,labels=trees.createDataSet()

myDat
Out[182]: [[1, 1, 'yes'], [1, 1, 'yes'], [1, 0, 'no'], [0, 1, 'no'], [0, 1, 'no']]

trees.chooseBestFeatTopSplit(myDat)
Out[183]: 0

通过数学计算演算以上数据集的最优增益,具体如下:

海洋生物数据集

整个样本集合的熵公式,如下:
Info= -\sum_{i=1}^{m}p_{i}\log_{2}p_{i}

为了简便运算,属于鱼类的设为y,不属于鱼类的设为n,具体见表格:

类别 属于鱼类y 不属于鱼类n 总共
个数 2 3 5
所占比例 \frac{2}{5} \frac{3}{5} 1

由此可知,区分是否鱼类的整个样本的熵为如下计算过程:
Info=p_{y}\log_{2}p_{y}+p_{n}\log_{2}p_{n}
   =\frac{2}{5}\log_{2}\frac{2}{5}+\frac{3}{5}\log_{2}\frac{3}{5}
   =0.971

假设用某一个字段A来划分,在这种划分规则下的熵为
Info_{A}= -\sum_{j=1}^{v}p_{j}.Info(A_{j})

由数据集可知道,数据集有特征1和特征2,因此我们分别计算特征1和特征2的熵.

假设用特征1来划分:
这里的特征1(不浮出水面是否可以生存)共有2个枚举值(是、否),表示划分成2组,那么本案例中特征1字段划分就是v=2的情况。p_{j}表示这种分组产生的概率,即不浮出水面是否可以生存各自的比例,具体可见如下表格:

为了简便运算,浮出水面可以生存的设为y_{1},浮出水面不可以生存的设为n_{1},则特征1的熵(Info_{A_{1}})计算结果如下:

Info_{A_{1}}=-[(浮出水面可以生存)+(浮出水面不可以生存)]
=-[(p_{y_{1}}×浮出水面可以生存分割熵)+(p_{n_{1}}×浮出水面不可以生存分割熵)]
= -(p_{y_{1}}×Info(A_{y_{1}})+p_{n_{1}}×Info(A_{n_{1}}))
=-(\frac{3}{5}×Info(A_{y_{1}})+\frac{2}{5}×Info(A_{n_{1}}))
=-[\frac{3}{5}×(\frac{2}{3}×\log_{2}\frac{2}{3}+\frac{1}{3}×\log_{2}\frac{1}{3})+\frac{2}{5}×(\frac{2}{2}×\log_{2}1)]
=0.551

假设用特征2来划分:
这里的特征2(是否有脚蹼)共有2个枚举值(是、否),表示划分成2组,那么本案例中特征2字段划分就是v=2的情况。p_{j}表示这种分组产生的概率,即是否有脚蹼各自的比例,具体可见如下表格:

为了简便运算,有脚蹼的设为y_{2},无脚蹼设为n_{2},则特征2的熵(Info_{A_{2}})计算结果如下:

Info_{A_{2}}=-[(有脚蹼)+(无脚蹼)]

=-[(p_{y_{2}}×有脚蹼分割熵)+(p_{n_{2}}×无脚蹼分割熵)]
= -(p_{y_{2}}×Info(A_{y_{2}})+p_{n_{2}}×Info(A_{n_{2}}))
=-(\frac{4}{5}×Info(A_{y_{2}})+\frac{1}{5}×Info(A_{n_{2}}))
=-[\frac{4}{5}×(\frac{1}{2}×\log_{2}\frac{1}{2}+\frac{1}{2}×\log_{2}\frac{1}{2})+\frac{1}{5}×(1×\log_{2}1)]
=0.8

信息增益公式如下:Gain(A)=Info - Info _{A}

由此可以得到以特征1为根的信息增量为:
Gain(A_{1})=Info - Info _{A_{1}}
=0.971-0.551
=0.42

由此可以得到以特征2为根的信息增量为:
Gain(A_{2})=Info - Info _{A_{2}}
=0.971-0.8
=0.171

因为Gain(A_{1})>Gain(A_{2}),所以特征1是最好的用于划分数据集的特征.

3.相关知识点:信息增量的小案例

假设相亲信息表如下所示:

网站ID 年龄(岁) 身高(cm) 年收入(万元) 学历 是否相亲
XXXXXXX 25 179 15 大专 N
XXXXXXX 33 190 19 大专 Y
XXXXXXX 28 180 18 硕士 Y
XXXXXXX 25 178 18 硕士 Y
XXXXXXX 46 177 100 硕士 N
XXXXXXX 40 170 70 本科 N
XXXXXXX 34 174 20 硕士 Y
XXXXXXX 36 181 55 本科 N
XXXXXXX 35 170 25 硕士 Y
XXXXXXX 30 180 35 本科 Y
XXXXXXX 28 174 30 本科 N
XXXXXXX 29 176 36 本科 Y

假设拿到真实的12个样本,由于网站ID这种信息对大龄女青年们做出相亲决策没有什么影响,所以直接忽略,下面来看后面的数据项。

整个样本集合的熵如下:
Info= -\sum_{i=1}^{m}p_{i}\log_{2}p_{i}
为了简便运算,属于相亲的设为y,不相亲的设为n,具体见表格:

类别 相亲y 不相亲n 总共
个数 7 5 12
所占比例 \frac{7}{12} \frac{5}{12} 1

由此可知,区分是否相亲的整个样本的熵为如下计算过程:
Info=p_{y}\log_{2}p_{y}+p_{n}\log_{2}p_{n}
   =\frac{7}{12}\log_{2}\frac{7}{12}+\frac{5}{12}\log_{2}\frac{5}{12}
   =0.98

现在要做的是挑出这个“树根”,挑出“树根”的原则是这一个点挑出来一刀切下去,要尽可能消除不确定性,最好一刀下去就把两个类分清楚,如果不行才会选择在下面的子节点再切一次,切的次数越少越好。`

假设用某一个字段A来划分,在这种划分规则下的熵为
Info_{A}= -\sum_{j=1}^{v}p_{j}.Info(A_{j})

以“学历”字段做分割的情况下,熵有什么变化。,具体运算过程如下:

Info_{A}是指要求的熵,右侧从1到v做加和,其中v表示一共划分为多少组,A字段有3个枚举值,表示划分成3组,如例子中“学历”字段就有3个枚举值,那么用“学历”字段划分就是v=3的情况。Pj表示这种分组产生的概率,也可以认为是一种权重,即3种学历各自占的比例,这里大专是2/12,本科是5/12,硕士是5/12。Info(A_{j})是在当前分组状态下的期望信息值。

Info_{A}=-[(大专项)+(本科项)+(硕士项)]
=-[(p(大专)×大专分割熵)+(p(本科)×本科分割熵)+(p(硕士)×硕士分割熵)]
=-[\frac{2}{12}×(\frac{1}{2}×\log_{2}\frac{1}{2}+\frac{1}{2}×\log_{2}\frac{1}{2})]-[\frac{5}{12}×(\frac{3}{5}×\log_{2}\frac{3}{5}+\frac{2}{5}×\log_{2}\frac{2}{5})]-[\frac{5}{12}×(\frac{4}{5}×\log_{2}\frac{4}{5}+\frac{1}{5}×\log_{2}\frac{1}{5})]
=0.872
则以“学历”字段作为根的信息增益如下:

Gain(学历)=Info-Info(学历)=0.98-0.872=0.108bit

如果希望挑选到的是增益最大的那种方式,那么还需要试试其他字段是否有更大的信息增益。

总结:
信息熵,是用来描述信息混乱程度或者说确定程度的一个值。熵越大说明信息混乱程度越高,做切割时越复杂,要切割若干次才能完成;熵越小说明信息混乱程度越低,做切割时越容易,切割次数也就越少。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271

推荐阅读更多精彩内容