最近刚把《机器学习实战》中的决策树过了一遍,接下来通过书中的实例,来温习决策树构造算法中的ID3算法。

海洋生物数据:

  不浮出水面是否可以生存 是否有脚蹼 属于鱼类
1
2
3
4
5

转换成数据集:

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

一、基础知识

1、熵

我把它简单的理解为用来度量数据的无序程度。数据越有序,熵值越低;数据越混乱或者分散,熵值越高。所以数据集分类后标签越统一,熵越低;标签越分散,熵越高。

更理论一点的解释:

熵被定义为信息的期望值,而如何理解信息?如果待分类的事物可能划分在多个分类中,则符号的信息定义为:

其中xi是选择该分类的概率,即 该类别个数 / 总个数。

为了计算熵,我们需要计算所有类别所有可能值包含的信息期望值,公式如下:

其中n是分类的数目。

计算给定数据集的香农熵:

def calcShannonEnt(dataSet):
numEntries = len(dataSet)
#创建字典,计算每种标签对应的样本数
labelCounts = {} for featVec in dataSet:
currentLabel = featVec[-1]
if currentLabel not in labelCounts.keys():
labelCounts[currentLabel] = 0
labelCounts[currentLabel] += 1
#根据上面的公式计算香农熵
shannonEnt = 0.0
for key in labelCounts:
prob = float(labelCounts[key])/numEntries
shannonEnt -= prob * log(prob,2)
return shannonEnt

运行代码,数据集myDat1只有两个类别,myDat2有三个类别:

>>> myDat1

[[1, 1, 'yes'], [1, 1, 'yes'], [1, 0, 'no'], [0, 1, 'no'], [0, 1, 'no']]

>>> trees.calcShannonEnt(myDat1)

0.9709505944546686

>>> myDat2

[[1, 1, 'maybe'], [1, 1, 'yes'], [1, 0, 'no'], [0, 1, 'no'], [0, 1, 'no']]

>>> trees.calcShannonEnt(myDat2)

1.3709505944546687

2、信息增益

信息增益可以衡量划分数据集前后数据(标签)向有序性发展的程度。

信息增益=原数据香农熵-划分数据集之后的新数据香农熵

二、按给定特征划分数据集

三个输入参数:待划分的数据集、划分数据集的特征位置、需要满足的当前特征的值

def splitDataSet(dataSet, axis, value):
retDataSet = []
for featVec in dataSet:
if featVec[axis] == value:
#获得除当前位置以外的特征元素
reducedFeatVec = featVec[:axis]
reducedFeatVec.extend(featVec[axis+1:])
#把每个样本特征堆叠在一起,变成一个子集合
retDataSet.append(reducedFeatVec)
return retDataSet

运行结果:

>>> myDat

[[1, 1, 'yes'], [1, 1, 'yes'], [1, 0, 'no'], [0, 1, 'no'], [0, 1, 'no']]

>>> trees.splitDataSet(myDat,0,1)

[[1, 'yes'], [1, 'yes'], [0, 'no']]

>>> trees.splitDataSet(myDat,0,0)

[[1, 'no'], [1, 'no']]

三、选择最好的数据集划分方式,即选择出最合适的特征用于划分数据集

def chooseBestFeatureToSplit(dataSet):
# 计算出数据集的特征个数
numFeatures = len(dataSet[0]) – 1
# 算出原始数据集的香农熵
baseEntropy = calcShannonEnt(dataSet)
bestInfoGain = 0.0; bestFeature = -1
for i in range(numFeatures):
# 抽取出数据集中所有第i个特征
featList = [example[i] for example in dataSet]
# 当前特征集合
uniqueVals = set(featList)
newEntropy = 0.0
# 根据特征划分数据集,并计算出香农熵和信息增益
for value in uniqueVals:
subDataSet = splitDataSet(dataSet, i, value)
prob = len(subDataSet)/float(len(dataSet))
newEntropy += prob * calcShannonEnt(subDataSet)
infoGain = baseEntropy - newEntropy # 返回最大信息增益的特征
if(infoGain > bestInfoGain):
bestInfoGain = infoGain
bestFeature = i
return bestFeature

四、如果数据集已经处理了所有特征属性,但是类标依然不是唯一的,此时采用多数表决的方式决定该叶子节点的分类。

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

五、创建决策树

接下来我们将利用上面学习的单元模块创建决策树。

def createTree(dataSet,labels):
classList = [example[-1] for example in dataSet]
# 如果划分的数据集只有一个类别,则返回此类别
if classList.count(classList[0]) == len(classList):
return classList[0]
# 如果使用完所有特征属性之后,类别标签仍不唯一,则使用majorityCnt函数,多数表决法,哪种类别标签多,则分为此类别
if len(dataSet[0]) == 1:
return majorityCnt(classList)
bestFeat = chooseBestFeatureToSplit(dataSet)
bestFeatLabel = labels[bestFeat]
myTree = {bestFeatLabel:{}}
del(labels[bestFeat])
featValues = [example[bestFeat] for example in dataSet]
uniqueVals = set(featValues)
for value in uniqueVals:
subLabels = labels[:]
myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value), subLabels)
return myTree

每次遇到递归问题总会头脑发昏,为了便于理解,我把一个创建决策树的处理过程重头到尾梳理了一遍。

原始数据集:

dataset: [[1, 1, 'yes'], [1, 1, 'yes'], [1, 0, 'no'], [0, 1, 'no'], [0, 1, 'no']]

labels: [no surfacing, flippers]

在调用createTree(dataSet,labels)函数之后,数据操作如下(每一个色块代表一次完整的createTree调用过程):

1、

dataset: [[1, 1, 'yes'], [1, 1, 'yes'], [1, 0, 'no'], [0, 1, 'no'], [0, 1, 'no']]

labels: [no surfacing, flippers]

classList=['yes', 'yes', 'no', 'no', 'no']

选择最好的特征来分类:bestFeat= 0

bestFeatLabel =no surfacing

构造树:myTree {'no surfacing': {}}

去除这个特征后,label=['flippers']

这个特征(no surfacing)的值:featValues= [1, 1, 1, 0, 0]

特征类别 uniqueVals=[0, 1]

(1)类别值为0的时候:

子标签=['flippers']

分出的子集 splitDataSet(dataSet, bestFeat, value) = [[1, 'no'], [1, 'no']]

myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value), subLabels)

1-1、

dataset: [[1, 'no'], [1, 'no']]

labels: ['flippers']

classList=['no', 'no']

满足classList中只有一个类别,返回no

myTree[bestFeatLabel][0] =’no’

myTree[bestFeatLabel] {0: 'no'}

也就是myTree {'no surfacing': {0: 'no'}}

(2)类别值为1的时候:

子标签=['flippers']

分出的子集 splitDataSet(dataSet, bestFeat, value) = [[1, 'yes'], [1, 'yes'], [0, 'no']]

myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value), subLabels)

1-2、

dataset: [[1, 'yes'], [1, 'yes'], [0, 'no']]

labels: ['flippers']

classList=['yes', 'yes', 'no']

选择最好的特征来分类:bestFeat= 0

bestFeatLabel = flippers

构造树:myTree {'flippers': {}}

去除这个特征后,label=[]

这个特征(flippers)的值:featValues= [1, 1, 0]

特征类别 uniqueVals=[0, 1]

(1)类别值为0的时候:

子标签=[]

分出的子集 splitDataSet(dataSet, bestFeat, value) = [['no']]

myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value), subLabels)

1-2-1、

dataset: [['no']]

labels: []

classList=['no']

满足classList中只有一个类别,返回no

myTree[bestFeatLabel][0] =’no’

myTree[bestFeatLabel] {0: 'no'}

也就是myTree {'flipper': {0: 'no'}}

(2)类别值为1的时候:

子标签=[]

分出的子集 splitDataSet(dataSet, bestFeat, value) = [['yes'], ['yes']]

myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value), subLabels)

1-2-2、

dataset: [['yes'], ['yes']]

labels: []

classList=['yes', 'yes']

满足classList中只有一个类别,返回yes

myTree[bestFeatLabel][1] =’yes’

myTree[bestFeatLabel] {0: 'no', 1: 'yes'}

也就是myTree: {'flippers': {0: 'no', 1: 'yes'}}

myTree[bestFeatLabel][1] ={'flippers': {0: 'no', 1: 'yes'}}

myTree[bestFeatLabel] {0: 'no', 1: {'flippers': {0: 'no', 1: 'yes'}}}

也就是myTree: {'no surfacing': {0: 'no', 1: {'flippers': {0: 'no', 1: 'yes'}}}}

例子中的决策树可视化图:

六、使用决策树做分类

def classify(inputTree, featLabels, testVec):
firstStr = inputTree.keys()[0]
secondDict = inputTree[firstStr]
featIndex = featLabels.index(firstStr)
for key in secondDict.keys():
if testVec[featIndex] == key:
if type(secondDict[key]).__name__=='dict':
classLabel = classify(secondDict[key], featLabels, testVec)
else: classLabel = secondDict[key]
return classLabel

输出结果:

>>> myTree

{'no surfacing': {0: 'no', 1: {'flippers': {0: 'no', 1: 'yes'}}}}

>>> labels

['no surfacing', 'flippers']

>>> trees.classify(myTree,labels,[1,0])

'no'

>>> trees.classify(myTree,labels,[1,1])

'yes'

七、 决策树的存储

构造决策树是很耗时的任务,然而用创建好的决策树解决分类问题,则可以很快的完成,可以通过使用pickle模块存储决策树。

def storeTree(inputTree, filename):
import pickle
fw = open(filename,'w')
pickle.dump(inputTree,fw)
fw.close() def grabTree(filename):
import pickle
fr = open(filename)
return pickle.load(fr)

参考资料:

[1] 《机器学习实战》

[2] 《机器学习实战》笔记——决策树(ID3)https://www.cnblogs.com/DianeSoHungry/p/7059104.html

机器学习之决策树(ID3)算法的更多相关文章

  1. 机器学习之决策树(ID3)算法与Python实现

    机器学习之决策树(ID3)算法与Python实现 机器学习中,决策树是一个预测模型:他代表的是对象属性与对象值之间的一种映射关系.树中每个节点表示某个对象,而每个分叉路径则代表的某个可能的属性值,而每 ...

  2. [机器学习实战] 决策树ID3算法

    1. 决策树特点: 1)优点:计算复杂度不高,输出结果易于理解,对中间值的缺失不敏感,可以处理不相关特征数据. 2)缺点:可能会产生过度匹配问题. 3)适用数据类型:数值型和标称型. 2. 一般流程: ...

  3. 机器学习实战 -- 决策树(ID3)

    机器学习实战 -- 决策树(ID3)   ID3是什么我也不知道,不急,知道他是干什么的就行   ID3是最经典最基础的一种决策树算法,他会将每一个特征都设为决策节点,有时候,一个数据集中,某些特征属 ...

  4. 02-21 决策树ID3算法

    目录 决策树ID3算法 一.决策树ID3算法学习目标 二.决策树引入 三.决策树ID3算法详解 3.1 if-else和决策树 3.2 信息增益 四.决策树ID3算法流程 4.1 输入 4.2 输出 ...

  5. 数据挖掘之决策树ID3算法(C#实现)

    决策树是一种非常经典的分类器,它的作用原理有点类似于我们玩的猜谜游戏.比如猜一个动物: 问:这个动物是陆生动物吗? 答:是的. 问:这个动物有鳃吗? 答:没有. 这样的两个问题顺序就有些颠倒,因为一般 ...

  6. 决策树ID3算法[分类算法]

    ID3分类算法的编码实现 <?php /* *决策树ID3算法(分类算法的实现) */ /* *求信息增益Grain(S1,S2) */ //-------------------------- ...

  7. 决策树---ID3算法(介绍及Python实现)

    决策树---ID3算法   决策树: 以天气数据库的训练数据为例. Outlook Temperature Humidity Windy PlayGolf? sunny 85 85 FALSE no ...

  8. 机器学习决策树ID3算法,手把手教你用Python实现

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是机器学习专题的第21篇文章,我们一起来看一个新的模型--决策树. 决策树的定义 决策树是我本人非常喜欢的机器学习模型,非常直观容易理解 ...

  9. Python四步实现决策树ID3算法,参考机器学习实战

    一.编写计算历史数据的经验熵函数 from math import log def calcShannonEnt(dataSet): numEntries = len(dataSet) labelCo ...

  10. 决策树ID3算法

    决策树 (Decision Tree)是在已知各种情况发生概率的基础上,通过构成 决策树 来求取净现值的期望值大于等于零的概率,评价项目风险,判断其可行性的决策分析方法,是直观运用概率分析的一种图解法 ...

随机推荐

  1. [java之设计模式]策略模式

    策略模式(strategy pattern) 定义>> 将一系列的算法封装到一些列的类里面,并且可以相互替换 作用>> 将算法的变化独立于客户端,将算法的指责和算法的行为分开, ...

  2. iOS audio不支持循环播放

    解决办法:监听播放完成事件(注意点,audio标签不能设置循环播放,去除标签 loop="loop"或者 loop="false",不然不走播放完成事件) $( ...

  3. new和delete的三种形式详解

    一.new操作符.delete操作符 class String { public: String(const char *str="") { if(str== NULL) { da ...

  4. MySQL学习【第九篇存储引擎】

    一.存储引擎介绍 1.我们知道mysql程序构成由连接层,sql层,存储引擎层.存储引擎层和磁盘进行交互,由其去取数据,而我们取得数据是表的形式展现出来,谁做的呢?就是存储引擎结构化成表的形式返回给用 ...

  5. 解决win10安装MySQL数据库出现服务无法启动的问题

    安装mysql的时候一直出现这个问题,在网上找了很多种方法,终于解决了这个问题. 我在官网下载的安装包解压后没有my.ini文件,需要自己添加(红字不要复制) [mysql]# 设置mysql客户端默 ...

  6. MySql多表关联,根据某列取前N条记录问题

    近来遇到一个问题:“MySql多表关联,根据某列取前N条记录”. 刚开始一直在想,SQL语句是否可以做到直接查询出来,但几经折磨,还是没能写出SQL语句,-------如果有大牛的话,望指点迷津.我把 ...

  7. CentOS 7紧急救援模式修改root用户密码的方法

    最近无聊在网上搜索linux系统root用户密码破解方法,看来很多朋友的博文,同时也试了一下,但是感觉他们写的还是不是很清晰.简洁,因此自己就心血来潮写了这篇博文,提供一个比较清晰的思路给新手,如果有 ...

  8. Ubuntu16.04上安装neo4j数据库

    什么是neo4j数据库? neo4j数据库是图数据库的一种,属于nosql的一种,常见的nosql数据库还有redis.memcached.mongDB等,不同于传统的关系型数据库,nosql数据也有 ...

  9. Linux 下 终端 相关的命令

    1. 概述 Linux 服务器, 通常可以由多个终端连接 简单介绍一些 终端 相关的操作 最终的目的, 是定位到某个终端, 然后把它 踢下来, 甚至可以不让他再次连接 2. 环境 操作系统 CentO ...

  10. 20155209 实验三 敏捷开发与XP实践

    20155209 实验三 敏捷开发与XP实践 实验内容 1. XP基础 2. XP核心实践 3. 相关工具 提交点一: 在IDEA中使用工具(Code->Reformate Code)把下面代码 ...