python实现ID3决策树算法


Posted in Python onDecember 20, 2017

决策树之ID3算法及其Python实现,具体内容如下

主要内容

决策树背景知识
决策树一般构建过程
ID3算法分裂属性的选择
ID3算法流程及其优缺点分析
ID3算法Python代码实现

1. 决策树背景知识

  决策树是数据挖掘中最重要且最常用的方法之一,主要应用于数据挖掘中的分类和预测。决策树是知识的一种呈现方式,决策树中从顶点到每个结点的路径都是一条分类规则。决策树算法最先基于信息论发展起来,经过几十年发展,目前常用的算法有:ID3、C4.5、CART算法等。

2. 决策树一般构建过程

  构建决策树是一个自顶向下的过程。树的生长过程是一个不断把数据进行切分细分的过程,每一次切分都会产生一个数据子集对应的节点。从包含所有数据的根节点开始,根据选取分裂属性的属性值把训练集划分成不同的数据子集,生成由每个训练数据子集对应新的非叶子节点。对生成的非叶子节点再重复以上过程,直到满足特定的终止条件,停止对数据子集划分,生成数据子集对应的叶子节点,即所需类别。测试集在决策树构建完成后检验其性能。如果性能不达标,我们需要对决策树算法进行改善,直到达到预期的性能指标。
  注:分裂属性的选取是决策树生产过程中的关键,它决定了生成的决策树的性能、结构。分裂属性选择的评判标准是决策树算法之间的根本区别。

3. ID3算法分裂属性的选择——信息增益

  属性的选择是决策树算法中的核心。是对决策树的结构、性能起到决定性的作用。ID3算法基于信息增益的分裂属性选择。基于信息增益的属性选择是指以信息熵的下降速度作为选择属性的方法。它以的信息论为基础,选择具有最高信息增益的属性作为当前节点的分裂属性。选择该属性作为分裂属性后,使得分裂后的样本的信息量最大,不确定性最小,即熵最小。
  信息增益的定义为变化前后熵的差值,而熵的定义为信息的期望值,因此在了解熵和信息增益之前,我们需要了解信息的定义。
  信息:分类标签xi 在样本集 S 中出现的频率记为 p(xi),则 xi 的信息定义为:−log2p(xi) 。
  分裂之前样本集的熵:E(S)=−∑Ni=1p(xi)log2p(xi),其中 N 为分类标签的个数。
  通过属性A分裂之后样本集的熵:EA(S)=−∑mj=1|Sj||S|E(Sj),其中 m 代表原始样本集通过属性A的属性值划分为 m 个子样本集,|Sj| 表示第j个子样本集中样本数量,|S| 表示分裂之前数据集中样本总数量。
  通过属性A分裂之后样本集的信息增益:InfoGain(S,A)=E(S)−EA(S)
  注:分裂属性的选择标准为:分裂前后信息增益越大越好,即分裂后的熵越小越好。

4. ID3算法

  ID3算法是一种基于信息增益属性选择的决策树学习方法。核心思想是:通过计算属性的信息增益来选择决策树各级节点上的分裂属性,使得在每一个非叶子节点进行测试时,获得关于被测试样本最大的类别信息。基本方法是:计算所有的属性,选择信息增益最大的属性分裂产生决策树节点,基于该属性的不同属性值建立各分支,再对各分支的子集递归调用该方法建立子节点的分支,直到所有子集仅包括同一类别或没有可分裂的属性为止。由此得到一棵决策树,可用来对新样本数据进行分类。

ID3算法流程:

(1) 创建一个初始节点。如果该节点中的样本都在同一类别,则算法终止,把该节点标记为叶节点,并用该类别标记。
(2) 否则,依据算法选取信息增益最大的属性,该属性作为该节点的分裂属性。
(3) 对该分裂属性中的每一个值,延伸相应的一个分支,并依据属性值划分样本。
(4) 使用同样的过程,自顶向下的递归,直到满足下面三个条件中的一个时就停止递归。
  A、待分裂节点的所有样本同属于一类。
  B、训练样本集中所有样本均完成分类。
  C、所有属性均被作为分裂属性执行一次。若此时,叶子结点中仍有属于不同类别的样本时,选取叶子结点中包含样本最多的类别,作为该叶子结点的分类。

ID3算法优缺点分析

优点:构建决策树的速度比较快,算法实现简单,生成的规则容易理解。
缺点:在属性选择时,倾向于选择那些拥有多个属性值的属性作为分裂属性,而这些属性不一定是最佳分裂属性;不能处理属性值连续的属性;无修剪过程,无法对决策树进行优化,生成的决策树可能存在过度拟合的情况。

5. ID3算法Python代码实现

# -*- coding: utf-8 -*-
__author__ = 'zhihua_oba'

import operator
from numpy import *
from math import log

#文件读取
def file2matrix(filename, attribute_num): #传入参数:文件名,属性个数
 fr = open(filename)
 arrayOLines = fr.readlines()
 numberOfLines = len(arrayOLines) #统计数据集行数(样本个数)
 dataMat = zeros((numberOfLines, attribute_num))
 classLabelVector = [] #分类标签
 index = 0
 for line in arrayOLines:
  line = line.strip() #strip() 删除字符串中的'\n'
  listFromLine = line.split() #将一个字符串分裂成多个字符串组成的列表,不带参数时以空格进行分割,当代参数时,以该参数进行分割
  dataMat[index, : ] = listFromLine[0:attribute_num] #读取数据对象属性值
  classLabelVector.append(listFromLine[-1]) #读取分类信息
  index += 1
 dataSet = [] #数组转化成列表
 index = 0
 for index in range(0, numberOfLines):
  temp = list(dataMat[index, :])
  temp.append(classLabelVector[index])
  dataSet.append(temp)
 return dataSet

#划分数据集
def splitDataSet(dataSet, axis, value):
 retDataSet = []
 for featvec in dataSet: #每行
  if featvec[axis] == value: #每行中第axis个元素和value相等 #删除对应的元素,并将此行,加入到rerDataSet
   reducedFeatVec = featvec[:axis]
   reducedFeatVec.extend(featvec[axis+1:])
   retDataSet.append(reducedFeatVec)
 return retDataSet

#计算香农熵 #计算数据集的香农熵 == 计算数据集类标签的香农熵
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

#根据香农熵,选择最优的划分方式 #根据某一属性划分后,类标签香农熵越低,效果越好
def chooseBestFeatureToSplit(dataSet):
 baseEntropy = calcShannonEnt(dataSet) #计算数据集的香农熵
 numFeatures = len(dataSet[0])-1
 bestInfoGain = 0.0 #最大信息增益
 bestFeature = 0 #最优特征
 for i in range(0, numFeatures):
  featList = [example[i] for example in dataSet] #所有子列表(每行)的第i个元素,组成一个新的列表
  uniqueVals = set(featList)
  newEntorpy = 0.0
  for value in uniqueVals: #数据集根据第i个属性进行划分,计算划分后数据集的香农熵
   subDataSet = splitDataSet(dataSet, i, value)
   prob = len(subDataSet)/float(len(dataSet))
   newEntorpy += prob*calcShannonEnt(subDataSet)
  infoGain = baseEntropy-newEntorpy #划分后的数据集,香农熵越小越好,即信息增益越大越好
  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]
 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[:]
  subDataSet = splitDataSet(dataSet, bestFeat, value)
  myTree[bestFeatLabel][value] = createTree(subDataSet, subLabels)
 return myTree

#测试算法:使用决策树,对待分类样本进行分类
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

def main():
 dataSet = file2matrix('test_sample.txt', 4)
 labels = ['attr01', 'attr02', 'attr03', 'attr04']
 labelsForCreateTree = labels[:]
 Tree = createTree(dataSet, labelsForCreateTree )
 testvec = [2, 3, 2, 3]
 print classify(Tree, labels, testvec)
if __name__ == '__main__':
  main()

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python 字符串操作方法大全
Mar 11 Python
Python学习笔记之常用函数及说明
May 23 Python
python&MongoDB爬取图书馆借阅记录
Feb 05 Python
深入学习python的yield和generator
Mar 10 Python
Python实现购物车功能的方法分析
Nov 10 Python
Python向MySQL批量插数据的实例讲解
Mar 31 Python
python实现寻找最长回文子序列的方法
Jun 02 Python
使用python进行拆分大文件的方法
Dec 10 Python
Apache部署Django项目图文详解
Jul 30 Python
浅谈在django中使用filter()(即对QuerySet操作)时踩的坑
Mar 31 Python
Python爬虫爬取微博热搜保存为 Markdown 文件的源码
Feb 22 Python
浅析python连接数据库的重要事项
Feb 22 Python
理解python中生成器用法
Dec 20 #Python
Python利用turtle库绘制彩虹代码示例
Dec 20 #Python
浅谈Python中range和xrange的区别
Dec 20 #Python
python机器学习实战之树回归详解
Dec 20 #Python
使用python 和 lint 删除项目无用资源的方法
Dec 20 #Python
python机器学习实战之K均值聚类
Dec 20 #Python
Python绘制3d螺旋曲线图实例代码
Dec 20 #Python
You might like
fleaphp下不确定的多条件查询的巧妙解决方法
2008/09/11 PHP
php array_search() 函数使用
2010/04/13 PHP
微信公众平台开发之天气预报功能
2015/08/31 PHP
PHP导出带样式的Excel示例代码
2016/08/28 PHP
php微信公众号开发(3)php实现简单微信文本通讯
2016/12/15 PHP
PHP生成图表pChart的示例解析
2020/07/31 PHP
javascript编程起步(第六课)
2007/02/27 Javascript
JavaScript 通过模式匹配实现重载
2010/08/12 Javascript
JavaScript全局函数使用简单说明
2011/03/11 Javascript
jquery用get实现ajax在ie里面刷新不进入后台解决方法
2013/08/12 Javascript
模拟jQuery中的ready方法及实现按需加载css,js实例代码
2013/09/27 Javascript
javascript使用smipleChart实现简单图表
2015/01/02 Javascript
JavaScript实现拖拽网页内元素的方法
2015/04/15 Javascript
javascript实现通过表格绘制颜色填充矩形的方法
2015/04/21 Javascript
再JavaScript的jQuery库中编写动画效果的指南
2015/08/13 Javascript
深入浅析knockout源码分析之订阅
2016/07/12 Javascript
JS控制静态页面之间传递参数获取参数并应用的简单实例
2016/08/10 Javascript
jQuery基于BootStrap样式实现无限极地区联动
2016/08/26 Javascript
javascript 分号总结及详细介绍
2016/09/24 Javascript
vue结合element-ui使用示例
2019/01/24 Javascript
JavaScript实现移动端拖动元素
2020/11/24 Javascript
Vue实现圆环进度条的示例
2021/02/06 Vue.js
Python端口扫描简单程序
2016/11/10 Python
python删除服务器文件代码示例
2018/02/09 Python
对Python字符串中的换行符和制表符介绍
2018/05/03 Python
Django restful framework生成API文档过程详解
2020/11/12 Python
pycharm配置QtDesigner的超详细方法
2021/01/25 Python
前端canvas水印快速制作(附完整代码)
2019/09/19 HTML / CSS
html5 Canvas实现图片旋转的示例
2018/01/15 HTML / CSS
Aquatalia官网:意大利著名鞋履品牌
2019/09/26 全球购物
德国亚洲食品网上商店:asiafoodland.de
2019/12/28 全球购物
Java如何格式化日期
2012/08/07 面试题
代码中finally中的代码会不会执行
2012/02/06 面试题
学雷锋先进个人事迹
2014/05/26 职场文书
2013年最新自荐信范文
2014/06/23 职场文书
小学校长汇报材料
2014/08/20 职场文书