机器学习之决策树(ID3)算法
最近刚把《机器学习实战》中的决策树过了一遍,接下来通过书中的实例,来温习决策树构造算法中的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)
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)
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)算法的更多相关文章
- 机器学习之决策树(ID3)算法与Python实现
机器学习之决策树(ID3)算法与Python实现 机器学习中,决策树是一个预测模型:他代表的是对象属性与对象值之间的一种映射关系.树中每个节点表示某个对象,而每个分叉路径则代表的某个可能的属性值,而每 ...
- [机器学习实战] 决策树ID3算法
1. 决策树特点: 1)优点:计算复杂度不高,输出结果易于理解,对中间值的缺失不敏感,可以处理不相关特征数据. 2)缺点:可能会产生过度匹配问题. 3)适用数据类型:数值型和标称型. 2. 一般流程: ...
- 机器学习实战 -- 决策树(ID3)
机器学习实战 -- 决策树(ID3) ID3是什么我也不知道,不急,知道他是干什么的就行 ID3是最经典最基础的一种决策树算法,他会将每一个特征都设为决策节点,有时候,一个数据集中,某些特征属 ...
- 02-21 决策树ID3算法
目录 决策树ID3算法 一.决策树ID3算法学习目标 二.决策树引入 三.决策树ID3算法详解 3.1 if-else和决策树 3.2 信息增益 四.决策树ID3算法流程 4.1 输入 4.2 输出 ...
- 数据挖掘之决策树ID3算法(C#实现)
决策树是一种非常经典的分类器,它的作用原理有点类似于我们玩的猜谜游戏.比如猜一个动物: 问:这个动物是陆生动物吗? 答:是的. 问:这个动物有鳃吗? 答:没有. 这样的两个问题顺序就有些颠倒,因为一般 ...
- 决策树ID3算法[分类算法]
ID3分类算法的编码实现 <?php /* *决策树ID3算法(分类算法的实现) */ /* *求信息增益Grain(S1,S2) */ //-------------------------- ...
- 决策树---ID3算法(介绍及Python实现)
决策树---ID3算法 决策树: 以天气数据库的训练数据为例. Outlook Temperature Humidity Windy PlayGolf? sunny 85 85 FALSE no ...
- 机器学习决策树ID3算法,手把手教你用Python实现
本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是机器学习专题的第21篇文章,我们一起来看一个新的模型--决策树. 决策树的定义 决策树是我本人非常喜欢的机器学习模型,非常直观容易理解 ...
- Python四步实现决策树ID3算法,参考机器学习实战
一.编写计算历史数据的经验熵函数 from math import log def calcShannonEnt(dataSet): numEntries = len(dataSet) labelCo ...
- 决策树ID3算法
决策树 (Decision Tree)是在已知各种情况发生概率的基础上,通过构成 决策树 来求取净现值的期望值大于等于零的概率,评价项目风险,判断其可行性的决策分析方法,是直观运用概率分析的一种图解法 ...
随机推荐
- [java之设计模式]策略模式
策略模式(strategy pattern) 定义>> 将一系列的算法封装到一些列的类里面,并且可以相互替换 作用>> 将算法的变化独立于客户端,将算法的指责和算法的行为分开, ...
- iOS audio不支持循环播放
解决办法:监听播放完成事件(注意点,audio标签不能设置循环播放,去除标签 loop="loop"或者 loop="false",不然不走播放完成事件) $( ...
- new和delete的三种形式详解
一.new操作符.delete操作符 class String { public: String(const char *str="") { if(str== NULL) { da ...
- MySQL学习【第九篇存储引擎】
一.存储引擎介绍 1.我们知道mysql程序构成由连接层,sql层,存储引擎层.存储引擎层和磁盘进行交互,由其去取数据,而我们取得数据是表的形式展现出来,谁做的呢?就是存储引擎结构化成表的形式返回给用 ...
- 解决win10安装MySQL数据库出现服务无法启动的问题
安装mysql的时候一直出现这个问题,在网上找了很多种方法,终于解决了这个问题. 我在官网下载的安装包解压后没有my.ini文件,需要自己添加(红字不要复制) [mysql]# 设置mysql客户端默 ...
- MySql多表关联,根据某列取前N条记录问题
近来遇到一个问题:“MySql多表关联,根据某列取前N条记录”. 刚开始一直在想,SQL语句是否可以做到直接查询出来,但几经折磨,还是没能写出SQL语句,-------如果有大牛的话,望指点迷津.我把 ...
- CentOS 7紧急救援模式修改root用户密码的方法
最近无聊在网上搜索linux系统root用户密码破解方法,看来很多朋友的博文,同时也试了一下,但是感觉他们写的还是不是很清晰.简洁,因此自己就心血来潮写了这篇博文,提供一个比较清晰的思路给新手,如果有 ...
- Ubuntu16.04上安装neo4j数据库
什么是neo4j数据库? neo4j数据库是图数据库的一种,属于nosql的一种,常见的nosql数据库还有redis.memcached.mongDB等,不同于传统的关系型数据库,nosql数据也有 ...
- Linux 下 终端 相关的命令
1. 概述 Linux 服务器, 通常可以由多个终端连接 简单介绍一些 终端 相关的操作 最终的目的, 是定位到某个终端, 然后把它 踢下来, 甚至可以不让他再次连接 2. 环境 操作系统 CentO ...
- 20155209 实验三 敏捷开发与XP实践
20155209 实验三 敏捷开发与XP实践 实验内容 1. XP基础 2. XP核心实践 3. 相关工具 提交点一: 在IDEA中使用工具(Code->Reformate Code)把下面代码 ...