最近刚把《机器学习实战》中的决策树过了一遍,接下来通过书中的实例,来温习决策树构造算法中的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. Oracle ddl 和 dml 操作

      ddl 操作 窗口设置用户权限的方法  Oracle的数据类型  按住Ctrl点击表名 ,可以鼠标操作  插入的数据需要满足创建表的检查  主表clazz删除数据从表设置级联也会一同删除 有约束也 ...

  2. jQuery对象与DOM对象的相互转化

    jQuery是一个类数组对象,DOM对象就是一个单独的DOM元素,他们都是可以操作的DOM元素. 一.jQuery对象转化为DOM对象 有以下两种方法: 方法一:利用数组下标的方式读取jQuery中的 ...

  3. js身份证校验

    通过js实现对15位或者18位身份证格式校验: 通过调用idCardNoUtil.checkeIdCardNo(idCardNo)传入身份证号码,实现校验. var idCardNoUtil = { ...

  4. Jquery实现表单动态加减、ajax表单提交

    一直在搞Java后台开发,记得刚工作那一两年时间搞过前后端交互开发,用的东西也是五花八门,当时觉得做页面展示给别人看,是很有成就的事情,不过现在感觉自己跟纯前端开发比起来弱爆了,不过如果你的目标是作为 ...

  5. Docker toolbox换源

    一 docker toolbox安装 略.... 阿里云加速器地址 https://jbriwmh3.mirror.aliyuncs.com 二 为docker toolbox更换国内源 docker ...

  6. pycharm社区版新建django文件不友好操作

    一.cmd操作 1.django-admin startproject (新建project名称) 2.在pycharm打开project,运行终端输入:python manage.py starta ...

  7. python多进程详解和协程

    1.由于python多线程适合于多IO操作,但不适合于cpu计算型工作,这时候可以通过多进程实现.python多进程简单实用 # 多进程,可以cpu保持一致,python多线程适合多io.对于高cpu ...

  8. django无法加载样式

    如果运行的环境是win10,那么首先应该考虑是否是如下问题 win10中Django后台admin无法加载CSS等样式 解决: 修改win10的注册表:[win+R输入Regedit] 因为你安装的某 ...

  9. 20155203 实验二《Java面向对象程序设计》实验报告

    20155203 实验二<Java面向对象程序设计>实验报告 一.实验内容 参考http://www.cnblogs.com/rocedu/p/6371315.html#SECUNITTE ...

  10. 20155328 2016-2017-2 《Java程序设计》第四周学习总结

    学号 2016-2017-2 <Java程序设计>第四周学习总结 教材学习内容总结 继承:避免多各类间重复定义行为,extends关键字表示继承后再扩充原本没有的行为.如果没有使用exte ...