Python实现决策树C4.5算法的示例


Posted in Python onMay 30, 2018

为什么要改进成C4.5算法

原理

C4.5算法是在ID3算法上的一种改进,它与ID3算法最大的区别就是特征选择上有所不同,一个是基于信息增益比,一个是基于信息增益。

之所以这样做是因为信息增益倾向于选择取值比较多的特征(特征越多,条件熵(特征划分后的类别变量的熵)越小,信息增益就越大);因此在信息增益下面加一个分母,该分母是当前所选特征的熵,注意:这里而不是类别变量的熵了。

这样就构成了新的特征选择准则,叫做信息增益比。为什么加了这样一个分母就会消除ID3算法倾向于选择取值较多的特征呢?

因为特征取值越多,该特征的熵就越大,分母也就越大,所以信息增益比就会减小,而不是像信息增益那样增大了,一定程度消除了算法对特征取值范围的影响。

实现

在算法实现上,C4.5算法只是修改了信息增益计算的函数calcShannonEntOfFeature和最优特征选择函数chooseBestFeatureToSplit。

calcShannonEntOfFeature在ID3的calcShannonEnt函数上加了个参数feat,ID3中该函数只用计算类别变量的熵,而calcShannonEntOfFeature可以计算指定特征或者类别变量的熵。

chooseBestFeatureToSplit函数在计算好信息增益后,同时计算了当前特征的熵IV,然后相除得到信息增益比,以最大信息增益比作为最优特征。

在划分数据的时候,有可能出现特征取同一个值,那么该特征的熵为0,同时信息增益也为0(类别变量划分前后一样,因为特征只有一个取值),0/0没有意义,可以跳过该特征。

Python实现决策树C4.5算法的示例

#coding=utf-8
import operator
from math import log
import time
import os, sys
import string

def createDataSet(trainDataFile):
 print trainDataFile
 dataSet = []
 try:
 fin = open(trainDataFile)
 for line in fin:
  line = line.strip()
  cols = line.split('\t')
  row = [cols[1], cols[2], cols[3], cols[4], cols[5], cols[6], cols[7], cols[8], cols[9], cols[10], cols[0]]
  dataSet.append(row)
  #print row
 except:
 print 'Usage xxx.py trainDataFilePath'
 sys.exit()
 labels = ['cip1', 'cip2', 'cip3', 'cip4', 'sip1', 'sip2', 'sip3', 'sip4', 'sport', 'domain']
 print 'dataSetlen', len(dataSet)
 return dataSet, labels

#calc shannon entropy of label or feature
def calcShannonEntOfFeature(dataSet, feat):
 numEntries = len(dataSet)
 labelCounts = {}
 for feaVec in dataSet:
 currentLabel = feaVec[feat]
 if currentLabel not in labelCounts:
  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 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
 
def chooseBestFeatureToSplit(dataSet):
 numFeatures = len(dataSet[0]) - 1 #last col is label
 baseEntropy = calcShannonEntOfFeature(dataSet, -1)
 bestInfoGainRate = 0.0
 bestFeature = -1
 for i in range(numFeatures):
 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 *calcShannonEntOfFeature(subDataSet, -1) #calc conditional entropy
 infoGain = baseEntropy - newEntropy
  iv = calcShannonEntOfFeature(dataSet, i)
 if(iv == 0): #value of the feature is all same,infoGain and iv all equal 0, skip the feature
 continue
 
 infoGainRate = infoGain / iv
 if infoGainRate > bestInfoGainRate:
  bestInfoGainRate = infoGainRate
  bestFeature = i
 return bestFeature
  
#feature is exhaustive, reture what you want label
def majorityCnt(classList):
 classCount = {}
 for vote in classList:
 if vote not in classCount.keys():
  classCount[vote] = 0
 classCount[vote] += 1
 return max(classCount)  
 
def createTree(dataSet, labels):
 classList = [example[-1] for example in dataSet]
 if classList.count(classList[0]) ==len(classList): #all data is the same label
 return classList[0]
 if len(dataSet[0]) == 1: #all feature is exhaustive
 return majorityCnt(classList)
 bestFeat = chooseBestFeatureToSplit(dataSet)
 bestFeatLabel = labels[bestFeat]
 if(bestFeat == -1): #特征一样,但类别不一样,即类别与特征不相关,随机选第一个类别做分类结果
 return classList[0] 
 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
 
def main():
 if(len(sys.argv) < 3):
 print 'Usage xxx.py trainSet outputTreeFile'
 sys.exit()
 data,label = createDataSet(sys.argv[1])
 t1 = time.clock()
 myTree = createTree(data,label)
 t2 = time.clock()
 fout = open(sys.argv[2], 'w')
 fout.write(str(myTree))
 fout.close()
 print 'execute for ',t2-t1
if __name__=='__main__':
 main()

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

Python 相关文章推荐
pandas or sql计算前后两行数据间的增值方法
Apr 20 Python
Python + selenium自动化环境搭建的完整步骤
May 19 Python
Python面向对象之反射/自省机制实例分析
Aug 24 Python
ubuntu16.04制作vim和python3的开发环境
Sep 23 Python
Windows下安装Scrapy
Oct 17 Python
Django ORM 聚合查询和分组查询实现详解
Aug 09 Python
Django使用中间件解决前后端同源策略问题
Sep 02 Python
Python绘制二维曲线的日常应用详解
Dec 04 Python
Pycharm 安装 idea VIM插件的图文教程详解
Feb 21 Python
python用opencv 图像傅里叶变换
Jan 04 Python
python爬虫框架feapde的使用简介
Apr 20 Python
python编程项目中线上问题排查与解决
Nov 01 Python
python实现决策树ID3算法的示例代码
May 30 #Python
浅谈Django中的数据库模型类-models.py(一对一的关系)
May 30 #Python
Python实现的读取电脑硬件信息功能示例
May 30 #Python
Python应用库大全总结
May 30 #Python
Django中反向生成models.py的实例讲解
May 30 #Python
Python RabbitMQ消息队列实现rpc
May 30 #Python
python日期时间转为字符串或者格式化输出的实例
May 29 #Python
You might like
咖啡与牛奶
2021/03/03 冲泡冲煮
php使用str_replace实现输入框回车替换br的方法
2014/11/24 PHP
javascript 写类方式之二
2009/07/05 Javascript
JQuery自定义事件的应用 JQuery最佳实践
2010/08/01 Javascript
js DOM 元素ID就是全局变量
2012/09/20 Javascript
javascript中call和apply方法浅谈
2013/09/27 Javascript
js返回上一页并刷新的多种实现方法
2014/02/26 Javascript
一个JavaScript的求爱小特效
2014/05/09 Javascript
jQuery通过控制节点实现仅在前台通过get方法完成参数传递
2015/02/02 Javascript
vue2.0路由切换后页面滚动位置不变BUG的解决方法
2018/03/14 Javascript
angularJs复选框checkbox选中进行ng-show显示隐藏的方法
2018/10/08 Javascript
angular4自定义表单控件[(ngModel)]的实现
2018/11/23 Javascript
微信小程序实现下拉刷新动画
2019/06/21 Javascript
使用VUE实现在table中文字信息超过5个隐藏鼠标移到时弹窗显示全部
2019/09/16 Javascript
Vue3.0 响应式系统源码逐行分析讲解
2019/10/14 Javascript
JS代码检查工具ESLint介绍与使用方法
2020/02/04 Javascript
Python三级目录展示的实现方法
2016/09/28 Python
深入理解NumPy简明教程---数组2
2016/12/17 Python
Python之自动获取公网IP的实例讲解
2017/10/01 Python
django使用html模板减少代码代码解析
2017/12/12 Python
python实现微信跳一跳辅助工具步骤详解
2018/01/04 Python
在CMD命令行中运行python脚本的方法
2018/05/12 Python
实用自动化运维Python脚本分享
2018/06/04 Python
Python lambda表达式用法实例分析
2018/12/25 Python
解决Pyinstaller 打包exe文件 取消dos窗口(黑框框)的问题
2019/06/21 Python
python中的TCP(传输控制协议)用法实例分析
2019/11/15 Python
python读写文件write和flush的实现方式
2020/02/21 Python
Python闭包及装饰器运行原理解析
2020/06/17 Python
Python偏函数Partial function使用方法实例详解
2020/06/17 Python
美国专注于健康商品的网站:eVitamins
2017/01/23 全球购物
美国花布包包品牌:Vera Bradley
2017/08/11 全球购物
美国在线家居装饰店:Belle&June
2018/10/24 全球购物
Java的for语句中break, continue和return的区别
2013/12/19 面试题
骨干教师个人总结
2015/02/11 职场文书
信访工作个人总结
2015/03/03 职场文书
法律意见书范文
2015/05/20 职场文书