写在前面的话

可怜了我这个系列的博客,写的这么好,花了很多心思去写的,却没有人知道欣赏。就像我这么好也没有人懂得欣赏,哈哈哈,我好不要脸。。。

如果您有任何地方看不懂的,那一定是我写的不好,请您告诉我,我会争取写的更加简单易懂!

如果您有任何地方看着不爽,请您尽情的喷,使劲的喷,不要命的喷,您的槽点就是帮助我要进步的地方!

1.划分数据集

1.1 基本概念

在度量数据集的无序程度的时候,分类算法除了需要测量信息熵,还需要划分数据集,度量花费数据集的熵,以便判断当前是否正确的划分了数据集。
我们将对每个特征数据集划分的结果计算一次信息熵,然后判断按照那个特征划分数据集是最好的划分方式。
也就是说,我们依次选取我们数据集当中的所有特征作为我们划定的特征,然后计算选取该特征时的信息增益,当信息增益最大时我们就选取对应信息增益最大的特征作为我们分类的最佳特征。

下面是我们的数据集:

我们用python语言表示出这个数据集
dataSet= [[1, 1, ‘yes’], [1, 1, ‘yes’], [1, 0, ‘no’], [0, 1, ‘no’], [0, 1, ‘no’]]
在这个数据集当中有两个特征,就是每个样本的第一列和第二列,最后一列是它们所属的分类。

我们划分数据集是为了计算根据那个特征我们可以得到最大的信息增益,那么根据这个特征来划分数据就是最好的分类方法。

因此我们需要遍历每一个特征,然后计算按照这种划分方式得出的信息增益。信息增益是指数据集在划分数据前后信息的变化量。


1.2 具体操作

划分数据集的方式我们首先选取第一个特征的第一个可能取值来筛选信息。然后再选取第一个特征的第二个可能的取值来划分我们的信息。之后我们再选取第二个特征的第一个可能的取值来划分数据集,以此类推。

e.g:
[[1, 1, ‘yes’], [1, 1, ‘yes’], [1, 0, ‘no’], [0, 1, ‘no’], [0, 1, ‘no’]]
这个是我们的数据集。
如果我们选取第一个特征值也就是需不需要浮到水面上才能生存来划分我们的数据,这里生物有两种可能,1就是需要,0就是不需要。那么第一个特征的取值就是两种。

如果我们按照第一个特征的第一个可能的取值来划分数据也就是当所有的样本的第一列取1的时候满足的样本,那就是如下三个:
[1, 1, ‘yes’], [1, 1, ‘yes’], [1, 0, ‘no’]
可以理解为这个特征为一条分界线,我们选取完这个特征之后这个特征就要从我们数据集中剔除,因为要把他理解为分界线。那么划分好的数据就是:

[[1, ‘yes’], [1, ‘yes’], [0, ‘no’]]

如果我们以第一个特征的第二个取值来划分数据集,也就是当所有样本的第二列取1的时候满足的样本,那么就是

[[1, 1, ‘yes’], [1, 1, ‘yes’], [0, 1, ‘no’], [0, 1, ‘no’]]
那么得到的数据子集就是下面这个样子:
[[1,’yes’],[1,’yes’],[1, ‘no’], [1, ‘no’]]


因此我们可以很容易的来构建出我们的代码:

下面我们来分析一下这段代码,

# 代码功能:划分数据集
def splitDataSet(dataSet,axis,value): #传入三个参数第一个参数是我们的数据集,是一个链表形式的数据集;第二个参数是我们的要依据某个特征来划分数据集retDataSet = [] #由于参数的链表dataSet我们拿到的是它的地址,也就是引用,直接在链表上操作会改变它的数值,所以我们新建一格链表来做操作for featVec in dataSet:if featVec[axis] == value: #如果某个特征和我们指定的特征值相等#除去这个特征然后创建一个子特征reduceFeatVec = featVec[:axis]reduceFeatVec.extend(featVec[axis+1:])#将满足条件的样本并且经过切割后的样本都加入到我们新建立的样本中retDataSet.append(reduceFeatVec)return retDataSet

总的来说,这段代码的功能就是按照某个特征的取值来划分数据集。

为方便您测试实验我们在贴出这段代码:


def splitDataSet(dataSet,axis,value):retDataSet = []for featVec in dataSet:if featVec[axis] == value:reduceFeatVec = featVec[:axis]reduceFeatVec.extend(featVec[axis+1:])retDataSet.append(reduceFeatVec)return retDataSet

在这里我们可以注意到一个关于链表的操作:
那就是extend 和append
它们的用法和区别如下所示:


下面我们再来测试一下我们的数据:

先给出实验的完整代码

#!/usr/bin/env python
# coding=utf-8
# author: chicho
# running: python trees.py
# filename : trees.py
from math import logdef createDataSet():dataSet = [[1,1,'yes'],[1,1,'yes'],[1,0,'no'],[0,1,'no'],[0,1,'no']]labels = ['no surfacing','flippers']return dataSet, labelsdef calcShannonEnt(dataSet):countDataSet = len(dataSet)labelCounts={}for featVec in dataSet:currentLabel=featVec[-1]if currentLabel not in labelCounts.keys():labelCounts[currentLabel] = 0labelCounts[currentLabel] += 1print labelCountsshannonEnt = 0.0for key in labelCounts:prob = float(labelCounts[key])/countDataSetshannonEnt -= prob * log(prob,2)return shannonEntdef splitDataSet(dataSet,axis,value):retDataSet = []for featVec in dataSet:if featVec[axis] == value:reduceFeatVec = featVec[:axis]reduceFeatVec.extend(featVec[axis+1:])retDataSet.append(reduceFeatVec)return retDataSet

我们输入下面代码测试一下,你可以在linux系统的终端中输入python或者是ipython 来进行测试:

In [1]: import treesIn [2]: reload(trees)
Out[2]: <module 'trees' from 'trees.pyc'>In [3]: myDat,labels=trees.createDataSet()In [4]: myDat
Out[4]: [[1, 1, 'yes'], [1, 1, 'yes'], [1, 0, 'no'], [0, 1, 'no'], [0, 1, 'no']]In [5]: trees.splitDataSet(myDat,0,1)
Out[5]: [[1, 'yes'], [1, 'yes'], [0, 'no']]In [6]: trees.splitDataSet(myDat,0,0)
Out[6]: [[1, 'no'], [1, 'no']]

知道怎么划分数据集之后,我们接下来的工作就是遍历整个样本集合的特征值,然后循环计算香农熵,找到最好的特征划分方式。


2.计算信息增益

我们主要是要找到划分数据前后的最大信息增益,然后找到根据那个特征来做划分,分类出来的效果更好。
下面给出代码是怎么实现的

我们来分析一下代码:

注意: 在使用这段代码的时候我们对处理的数据是有要求的。
1.数据集必须是链表的表示出来的
2.数据集的每一个样本也是链表形式
3.数据集的每一个样本都必须是前面的所有列都是样本的特征值的取值范围,所有样本的最后一列是样本的类别。
4.每个样本的列数必须相同

首先我们的样本集合是:

dataSet = [[1,1,’yes’],
[1,1,’yes’],
[1,0,’no’],
[0,1,’no’],
[0,1,’no’]] # 我们定义了一个list来表示我们的数据集,这里的数据对应的是上表中的数据


我们的目的已经很明确了,就是依次遍历每一个特征,在这里我们的特征只有两个,就是需不需要浮出水面,有没有脚蹼。然后计算出根据每一个特征划分产生的数据集的熵,和初始的数据集的熵比较,我们找出和初始数据集差距最大的。那么这个特征就是我们划分时最合适的分类特征。

def chooseBestFeatureToSplit(dataSet):numFeatures = len(dataSet[0])-1 # 获取我们样本集中的某一个样本的特征数(因为每一个样本的特征数是相同的,相当于这个代码就是我们可以作为分类依据的所有特征个数)我们的样本最后一列是样本所属的类别,所以要减去类别信息,在我们的例子中特征数就是2baseEntropy = calcShannonEnt(dataSet) #计算样本的初始香农熵bestInfoGain =0.0 #初始化最大信息增益bestFeature = -1 #和最佳划分特征for i in range(numFeatures): # range(2)那么i的取值就是0,1。 在这里i表示的我们的第几个特征featList = [sample[i] for sample in dataSet]# 我们首先遍历整个数据集,首先得到第一个特征值可能的取值,然后把它赋值给一个链表,我们第一个特征值取值是[1,1,1,0,0],其实只有【1,0】两个取值uniqueVals = set(featList)#我们使用集合这个数据类型删除多余重复的原始使得其中只有唯一的值。#执行的结果如下所示:```In [8]: featList=[1,1,1,0,0]In [9]: uniqueVals=set(featList)In [10]: uniqueValsOut[10]: {0, 1}```newEntropy = 0.0for value in uniqueVals: #uniqueVals中保存的是我们某个样本的特征值的所有的取值的可能性subDataSet = splitDataSet(dataSet,i,value)# 在这里划分数据集,比如说第一个特征的第一个取值得到一个子集,第一个特征的特征又会得到另一个特征。当然这是第二次循环prob = len(subDataSet)/float(len(dataSet))#我们以第一个特征来说明,根据第一个特征可能的取值划分出来的子集的概率newEntropy += prob * calcShannonEnt(subDataSet)# 这里比较难理解我们下面在详细说明infoGain = baseEntropy - newEntropy # 计算出信息增益#找出最佳信息增益,是个学计算机的小朋友都懂吧,哨兵法if(infoGain > bestInfoGain):bestInfoGain = infoGainbestFeature = ireturn bestFeature

被我标注的有点恶心,我在贴一遍代码,方便大家测试:

def chooseBestFeatureToSplit(dataSet):numFeatures = len(dataSet[0])-1baseEntropy = calcShannonEnt(dataSet)bestInfoGain =0.0bestFeature = -1for i in range(numFeatures):featList = [sample[i] for sample in dataSet]uniqueVals = set(featList)newEntropy = 0.0for value in uniqueVals:subDataSet = splitDataSet(dataSet,i,value)prob = len(subDataSet)/float(len(dataSet))newEntropy += prob * calcShannonEnt(subDataSet)infoGain = baseEntropy - newEntropyif(infoGain > bestInfoGain):bestInfoGain = infoGainbestFeature = ireturn bestFeature

难点
下面我们来重点解释一下刚才我们没有说的那句代码:

newEntropy += prob * calcShannonEnt(subDataSet)

为什么根据这个代码就可以计算出划分子集的熵了呢?
首先我们还是要回顾一下计算数学期望的方法,我们必须明确熵是信息的数学期望。

对于随机变量要计算它的数学期望我们是这样来计算的:

X X1 X2
p p1 p2

E(x)=P1*X1 + P2 *X2
我么都以第一特征值来说明问题
同理,我们可以先计算出按照第一个特征值的第一个可能取值划分满足的子集的概率,和第一个特征值的第二个可能取值划分满足子集的概率。之后分别乘以它们子集计算出的香农熵。

香农熵 H1 H2
特征值划分出子集概率 p1 p2

E(H)=H1×P1+H2×P2

e.g. 第一个特征为例
这是我们的数据集

我们按照第一个特征的第一个取值划分得到的数据集是:

得到了两个数据集,那么占总的数据集就是2/5
我们按照第一个特征的第二个取值划分得到的数据集是:


得到了三个数据集,那么占总的数据集就是3/5

我们分别来计算一下它们的香农熵


××××××
我们观察一下数据,也充分的验证了分类越多,香农熵会越大,当我们的分类只有一类是香农熵是0
××××××

我们采用列表法来计算一下熵:

某个特征的不同取值对应的香农熵 0.0 0.9182958340544896
特征值划分出子集概率 0.4 0.6

根据期望的定义,我们在第一章讲过的公式,那么就可以计算出这个特征的信息熵


我们来测试一下结果:


In [1]: import treesIn [2]: reload(trees)
Out[2]: <module 'trees' from 'trees.pyc'>In [3]: myDat,labels=trees.createDataSet()In [4]: myDat
Out[4]: [[1, 1, 'yes'], [1, 1, 'yes'], [1, 0, 'no'], [0, 1, 'no'], [0, 1, 'no']]In [5]: trees.chooseBestFeatureToSplit(myDat)
#总的数据分类
{'yes': 2, 'no': 3}
#按照第一个特征的第一个取值来划分
{'no': 2}
#按照第一个特征的第二个取值来划分
{'yes': 2, 'no': 1}
##按照第二个特征的第一个取值来划分
{'no': 1}
#按照第二个特征的第二个取值来划分
{'yes': 2, 'no': 2}
Out[5]: 0

我们可以看出计算的结果是根据第一个特征划分比较好。

这个其实也很明显了,我们可以观察一下我们的数据按照第一个特征来划分,当特征为1时生物分组有两个属于鱼类,一个属于非鱼类,另一个分组全部属于非鱼类。
如果按照第二个特征分类,一组中两个属于鱼类,两个属于非鱼来,另一组中只有一个是非鱼类。也就是按照第二特征来划分,错误率比较大。


完整的代码:

#!/usr/bin/env python
# coding=utf-8
# author: chicho
# running: python trees.py
# filename : trees.py
from math import logdef createDataSet():dataSet = [[1,1,'yes'],[1,1,'yes'],[1,0,'no'],[0,1,'no'],[0,1,'no']]labels = ['no surfacing','flippers']return dataSet, labelsdef calcShannonEnt(dataSet):countDataSet = len(dataSet)labelCounts={}for featVec in dataSet:currentLabel=featVec[-1]if currentLabel not in labelCounts.keys():labelCounts[currentLabel] = 0labelCounts[currentLabel] += 1print labelCountsshannonEnt = 0.0for key in labelCounts:prob = float(labelCounts[key])/countDataSetshannonEnt -= prob * log(prob,2)return shannonEntdef splitDataSet(dataSet,axis,value):retDataSet = []for featVec in dataSet:if featVec[axis] == value:reduceFeatVec = featVec[:axis]reduceFeatVec.extend(featVec[axis+1:])retDataSet.append(reduceFeatVec)return retDataSetdef chooseBestFeatureToSplit(dataSet):numFeatures = len(dataSet[0])-1baseEntropy = calcShannonEnt(dataSet)bestInfoGain =0.0bestFeature = -1for i in range(numFeatures):featList = [sample[i] for sample in dataSet]uniqueVals = set(featList)newEntropy = 0.0for value in uniqueVals:subDataSet = splitDataSet(dataSet,i,value)prob = len(subDataSet)/float(len(dataSet))newEntropy += prob * calcShannonEnt(subDataSet)infoGain = baseEntropy - newEntropyif(infoGain > bestInfoGain):bestInfoGain = infoGainbestFeature = ireturn bestFeature

写在后面的话

要么就不做,要做就做最好

决策树算法(四)——选取最佳特征划分数据集相关推荐

  1. ML之DT:基于DT决策树算法(对比是否经特征筛选FS处理)对Titanic(泰坦尼克号)数据集进行二分类预测

    ML之DT:基于DT决策树算法(对比是否经特征筛选FS处理)对Titanic(泰坦尼克号)数据集进行二分类预测 目录 输出结果 设计思路 核心代码 输出结果 初步处理后的 X_train: (984, ...

  2. 决策树算法笔记整理1 - 如何划分?(信息熵,不纯度及信息增益)

    1. 帮助理解的前置case 1.1 case1:相亲 参考CSDN其他blog 决策树,顾名思义,是一种树,一种依托于策略抉择而建立起来的树. 套用俗语,决策树分类的思想类似于找对象.现想象一个女孩 ...

  3. 决策树算法(一)——一些重要的数学概念

    写在前面的话 趁着现在我还是高中数理化老师,偶尔兼职英语老师的时候赶紧抓紧时间写点有关计算机科学技术的东西.一来是表示我对计算机的热爱,二来,当然是最重要的咯,满足一下我强大的虚荣心.哈哈哈哈!想想高 ...

  4. 机器学习-有监督学习-分类算法:决策树算法【CART树:分类树(基于信息熵;分类依据:信息增益、信息增益率、基尼系数)、回归树(基于均方误差)】【损失函数:叶节点信息熵和】【对特征具有很好的分析能力】

    一.决策树概述 注:生产实践中,不使用决策树,太简单,而是使用决策树的升级版:集成学习算法. 集成学习算法有: Random Forest(随机森林) Extremely Randomized For ...

  5. 从零开始学习机器学习五:决策树算法特征工程

    决策树&特征工程 目标 1 简介 1.1 认识决策树 2 分类原理 2.1 熵 2.2 决策树的划分依据一-信息增益 2.3 决策树的划分依据二-信息增益率 2.4 决策树的划分依据三-基尼值 ...

  6. 决策树算法之鸢尾花特征分类可视化详解【机器学习】

    文章目录 一.前言 1.1 本文原理 1.2 本文目的 二.实验过程 2.1 使用scikit-learn机器学习包的决策树算法,使用4个特征对鸢尾花进行分类: 2.2使用ID3算法对天气与踢球数据集 ...

  7. FlyAI小课堂:python机器学习笔记:深入学习决策树算法原理

    分类技术(或分类法)是一种根据输入数据建立分类模型的系统方法,分类法的例子包括决策分类法,基于规则的分类法,神经网络,支持向量机和朴素贝叶斯分类法.这些技术都使用一种学习算法(learning alg ...

  8. 机器学习基础 决策树算法

    文章目录 一.决策树算法简介 二.决策树分类原理 1. 熵 1.1 概念 1.2 案例 2. 决策树的划分依据一----信息增益 2.1 概念 2.2 案例 3. 决策树的划分依据二----信息增益率 ...

  9. 决策树算法梳理以及python实现

    1.信息论基础 1.1 熵 熵:用通俗点的话来说就是一个衡量混乱程度的单位.例如一个杯子A里只倒了啤酒,而另 一个杯子B里倒了啤酒,白酒, 红酒,那么我们说杯子A的熵值比杯子B的熵值小 \ 专业解释: ...

最新文章

  1. getordefault java_Java map.getOrDefault()方法的用法详解
  2. springboot 获取web服务端口_我是这样使用SpringBoot(WEB服务)
  3. Linux 6.4 partprobe出现warning问题
  4. linux桌面版本安装MSDM,Parallel_s desktop怎么安装linux系统
  5. linux下activityMQ安装
  6. Minecraft Forge 安装
  7. xp计算机用户名和密码忘记了怎么办,XP系统开机密码忘记了怎么办?
  8. 图片去水印在线-图片去水印无痕迹的app
  9. 北京理工大学计算机科学与技术培养方案,王全玉_北京理工大学计算机学院
  10. 云手机哪个好用最流畅?红手指、双子星、雷电云手机性价比推荐排行
  11. “清华学霸计划表”刷爆家长群:自律的孩子有多棒?你想象不到
  12. 代码管理平台gitlab
  13. 把笔记本变为无线路由器使用(win7无需软件)
  14. 学习python需要什么?
  15. 崔斯坦和依索德(Tristan and Isolde)
  16. 造成计算机系统不安全的因素,造成计算机系统不安全的因素包括()。
  17. 名悦集团:春节小长假后汽车保养该怎么做
  18. 10、Win下,Qt更改电脑IP、子网掩码和网关
  19. 如何通过clickhouse找出灌水用户
  20. 【中国标准】 DRA音频标准是什么概念?

热门文章

  1. 网易严选 x 网易有数:数据产品+数据中台双引擎模式实践
  2. 我有点不喜欢分布式中的TCC模式了
  3. 为什么你老是讲不清楚js的继承模式
  4. 用它调试线上bug,真得劲!
  5. 为什么有的人还不到三十岁,就对工作失去了兴趣呢?
  6. 一次 HashSet 所引起的并发问题
  7. Scrum Mastery:产品开发中如何优化产品价值?
  8. 强烈推荐8款高质量的网站,可以解决很多问题
  9. c是编译语言吗,将语言编译为C是一个好主意吗?
  10. 用Leangoo看板工具做办公室采购流程管理