一个简单的C4.5算法,采用Python语言
Test1.py 主要是用来运行的 代码如下:
- # -*- coding: utf-8 -*-
- from math import log
- import operator
- import treePlotter
- def calcShannonEnt(dataSet):
- """
- 输入:数据集
- 输出:数据集的香农熵
- 描述:计算给定数据集的香农熵;熵越大,数据集的混乱程度越大
- """
- # 数据集个数
- numEntries = len(dataSet)
- #print("dd",numEntries)
- # 标签个数
- labelCounts = {}
- for featVec in dataSet:
- # 获取每一行的结果 也就是yes or no
- currentLabel = featVec[-1]
- # print('e',currentLabel)
- # 判断我获取的这个yes or no 在不在labelCounts字典中 如果不在创建新的设置为0
- if currentLabel not in labelCounts.keys():
- labelCounts[currentLabel] = 0
- labelCounts[currentLabel] += 1
- #print('r',labelCounts)
- shannonEnt = 0.0
- for key in labelCounts:
- # 计算类别信息熵
- prob = float(labelCounts[key])/numEntries
- shannonEnt -= prob * log(prob, 2)
- #print('----',shannonEnt)
- return shannonEnt
- # 分别按照这几个属性来计算信息熵 找出最大的,最后按照这一个来划分。
- def splitDataSet(dataSet, axis, value):
- """
- 输入:数据集,选择维度,选择值
- 输出:划分数据集
- 描述:按照给定特征划分数据集;去除选择维度中等于选择值的项
- """
- retDataSet = []
- # 这个时候 dataSet 还是完整的
- for featVec in dataSet:
- # print(axis,featVec)
- # print('A',featVec[axis],"是不是等于",value)
- if featVec[axis] == value:
- reduceFeatVec = featVec[:axis]
- # print("B",reduceFeatVec,"此时的维度:",axis)
- reduceFeatVec.extend(featVec[axis+1:])
- retDataSet.append(reduceFeatVec)
- # print('GG',retDataSet)
- return retDataSet
- def chooseBestFeatureToSplit(dataSet):
- """
- 输入:数据集
- 输出:最好的划分维度
- 描述:选择最好的数据集划分维度
- """
- # 特征数量 也就是字段个数
- numFeatures = len(dataSet[0]) - 1
- ###################################################################
- # (1)信息增益
- # print('cc',numFeatures)
- # 信息增益实际上是ID3算法中用来进行属性选择度量的。
- # 它选择具有最高信息增益的属性来作为节点N的分裂属性。
- # 该属性使结果划分中的元组分类所需信息量最小。
- # 对D中的元组分类所需的期望信息为下式:
- baseEntropy = calcShannonEnt(dataSet) # 香农熵
- # print('z',baseEntropy)
- bestInfoGainRatio = 0.0 # 最好的熵
- bestFeature = -1 # 最好的特征
- for i in range(numFeatures):
- featList = [example[i] for example in dataSet]
- uniqueVals = set(featList)
- # print('s',i,uniqueVals)
- newEntropy = 0.0
- splitInfo = 0.0
- for value in uniqueVals:
- # 划分数据集
- # print("Bn",i,value)
- subDataSet = splitDataSet(dataSet, i, value)
- #print("After",subDataSet,i,value)
- prob = len(subDataSet)/float(len(dataSet))
- # 现在假定按照属性A划分D中的元组,且属性A将D划分成v个不同的类。
- # 在该划分之后,为了得到准确的分类还需要的信息由下面的式子度量
- newEntropy += prob * calcShannonEnt(subDataSet)
- # 信息增益定义为原来的信息需求(即仅基于类比例)与新需求(即对A划分之后得到的)之间的差
- splitInfo += -prob * log(prob, 2)
- # 信息增益
- infoGain = baseEntropy - newEntropy
- ##########################################################################
- if (splitInfo == 0): # 修复溢出错误
- continue
- #########################################################################
- # (2)信息增益率
- # 训练数据集D划分成对应于属性A测试的v个输出的v个划分产生的信息。信息增益率定义:
- infoGainRatio = infoGain / splitInfo
- # 选择具有最大增益率的属性作为分裂属性。
- if (infoGainRatio > bestInfoGainRatio):
- bestInfoGainRatio = infoGainRatio
- bestFeature = i
- return bestFeature
- def majorityCnt(classList):
- """
- 输入:分类类别列表
- 输出:子节点的分类
- 描述:数据集已经处理了所有属性,但是类标签依然不是唯一的,
- 采用少数服从多数的原则决定该子节点的分类
- """
- ''' 找出数量最多的分类 '''
- # 分类字典
- classCount = {}
- for vote in classList:
- if vote not in classCount.keys():
- classCount[vote] = 0
- classCount[vote] += 1
- # 创建键值为classList中唯一值的数据字典,字典对象存储了classList中每个类标签出现的频率,最后利用operator操作键值排序字典,并返回出现次数最多的分类名称。
- # iteritems:迭代器
- # operator模块提供的itemgetter函数用于获取对象的哪些维的数据,参数为一些序号(即需要获取的数据在对象中的序号)
- # sorted() 是Python内置的一个排序函数,它会从一个"迭代器"返回一个排好序的新列表。
- sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reversed=True)
- return sortedClassCount[0][0]
- # 创建决策树 参数:数据集、标签
- def createTree(dataSet, labels):
- """
- 输入:数据集,特征标签
- 输出:决策树
- 描述:递归构建决策树,利用上述的函数
- """
- # 截取dataSet的最后一行
- classList = [example[-1] for example in dataSet]
- # 数据集都是同一类的情况
- if classList.count(classList[0]) == len(classList):
- return classList[0]
- # 遍历完所有特征时返回出现次数最多的
- #print('bb',dataSet[1])
- # 如果数据集只有一个特征的情况
- if len(dataSet[0]) == 1:
- return majorityCnt(classList)
- # 最大增益率的属性作为分裂属性
- bestFeat = chooseBestFeatureToSplit(dataSet) # 最好的特征
- # print('bestFeat',bestFeat) # 0 2 当选择0(outlook)之后 剩下的012中选择2(windy)中
- bestFeatLabel = labels[bestFeat] # 最好的分类
- myTree = {bestFeatLabel:{}}
- # print(myTree) # {'outlook': {}} {'windy': {}}
- del(labels[bestFeat])
- # 得到列表包括节点所有的属性值
- featValues = [example[bestFeat] for example in dataSet]
- # print('featValues',featValues)
- uniqueVals = set(featValues)
- # print('uniqueVals',uniqueVals)
- for value in uniqueVals:
- # 去掉前面标签之后剩下的标签
- subLabels = labels[:]
- # print('subLabels',subLabels)
- myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value), subLabels)
- # print('myTree',myTree)
- return myTree
- def classify(inputTree, featLabels, testVec):
- """
- 输入:决策树,分类标签,测试数据
- 输出:决策结果
- 描述:跑决策树
- """
- firstStr = list(inputTree.keys())[0]
- # print('t2',firstStr)
- secondDict = inputTree[firstStr]
- #print('t3',secondDict)
- featIndex = featLabels.index(firstStr)
- # print('t4',featIndex)
- for key in secondDict.keys():
- #print('key',key)
- if testVec[featIndex] == key:
- #print('testVec[featIndex]',testVec[featIndex])
- if type(secondDict[key]).__name__ == 'dict':
- classLabel = classify(secondDict[key], featLabels, testVec)
- else:
- classLabel = secondDict[key]
- # print('t5',classLabel)
- return classLabel
- # 通过输入的决策树和对应的标签 来对测试集合 进行预测
- def classifyAll(inputTree, featLabels, testDataSet):
- """
- 输入:决策树,分类标签,测试数据集
- 输出:决策结果
- 描述:跑决策树
- """
- # 空列表
- classLabelAll = []
- for testVec in testDataSet:
- # print('t1',testVec)
- # 将预测结果插入到classLabelAll中
- classLabelAll.append(classify(inputTree, featLabels, testVec))
- # print("t6",classLabelAll)
- return classLabelAll
- # 训练集
- def createDataSet():
- """
- 天气情况 outlook-> sunny | overcast | rain
- 温度情况 temperature-> hot | mild | cool
- 湿度情况 humidity-> high | normal
- 风力情况 windy-> false | true
- """
- ######## no or yes is play golf ???
- dataSet = [["sunny", "hot", "high", "false", 'no'],
- ["sunny", "hot", "high", "true", 'no'],
- ["overcast", "hot", "high", "false", 'yes'],
- ["rain", "mild", "high", "false", 'yes'],
- ["rain", "cool", "normal", "false", 'yes'],
- ["rain", "cool", "normal", "true", 'no'],
- ["overcast","cool", "normal", "true", 'no'],
- ["rain", "hot", "high", "true", 'yes'],
- ["sunny", "mild", "high", "true", 'no'],
- ["rain", "hot", "normal", "true", 'yes'],
- ["overcast","mild", "high", "false", 'no']]
- # 对应的标签
- labels = ['outlook', 'temperature', 'humidity', 'windy']
- return dataSet, labels
- # 测试集
- def createTestSet():
- testSet = [["sunny", "mild", "high", "false"],
- ["sunny", "cool", "normal", "false"],
- ["rain", "mild", "normal", "false"],
- ["sunny", "mild", "normal", "true"],
- ["overcast","mild", "high", "true"],
- ["rain", "hot", "normal", "true"],
- ["sunny", "mild", "normal", "false"],
- ["rain", "hot", "high", "true"],
- ["sunny", "mild", "high", "true"],
- ["rain", "hot", "normal", "true"],
- ["overcast", "mild", "high", "false"],
- ["rain", "mild", "high", "true"]]
- return testSet
- #主函数 定义
- def main():
- dataSet, labels = createDataSet()
- labels_tmp = labels[:] # 拷贝 labels
- Tree = createTree(dataSet, labels_tmp)
- print('Tree:\n', Tree)
- treePlotter.createPlot(Tree)
- print('------------------------------')
- # 获取测试集 进行预测
- testSet = createTestSet()
- print('classifyResult:\n', classifyAll(Tree, labels, testSet))
- # 调用主函数
- if __name__ == '__main__':
- main()
treePlotter.py 用来画决策树。 代码如下所示:
- import matplotlib.pyplot as plt
- # 定义文本框和箭头格式
- decisionNode = dict(boxstyle="sawtooth", fc="0.8")
- leafNode = dict(boxstyle="round4", fc="0.8")
- arrow_args = dict(arrowstyle="<-")
- # 绘制带箭头的注释
- def plotNode(nodeTxt, centerPt, parentPt, nodeType):
- createPlot.ax1.annotate(nodeTxt, xy=parentPt, xycoords='axes fraction', \
- xytext=centerPt, textcoords='axes fraction', \
- va="center", ha="center", bbox=nodeType, arrowprops=arrow_args)
- ''' 获得决策树的叶节点数 '''
- def getNumLeafs(myTree):
- numLeafs = 0
- # fistStr获得字典的键 代表树根
- firstStr = list(myTree.keys())[0] # 头结点
- # print('firstStr',firstStr)
- secondDict = myTree[firstStr] # 取出头结点的的字典
- for key in secondDict.keys(): # 测试节点的数据类型是否为字典
- if type(secondDict[key]).__name__ == 'dict':
- numLeafs += getNumLeafs(secondDict[key])
- else:
- numLeafs += 1
- return numLeafs
- ''' 求树的深度 '''
- def getTreeDepth(myTree):
- maxDepth = 0
- firstStr = list(myTree.keys())[0] # 头结点
- secondDict = myTree[firstStr]
- for key in secondDict.keys(): # 测试节点的数据类型是否为字典
- if type(secondDict[key]).__name__ == 'dict':
- thisDepth = getTreeDepth(secondDict[key]) + 1
- else:
- thisDepth = 1
- if thisDepth > maxDepth:
- maxDepth = thisDepth
- return maxDepth
- ''' 在父子节点之间填充文本信息 '''
- def plotMidText(cntrPt, parentPt, txtString):
- xMid = (parentPt[0] - cntrPt[0]) / 2.0 + cntrPt[0]
- yMid = (parentPt[1] - cntrPt[1]) / 2.0 + cntrPt[1]
- createPlot.ax1.text(xMid, yMid, txtString)
- ''' 根节点坐标 '''
- def plotTree(myTree, parentPt, nodeTxt):
- numLeafs = getNumLeafs(myTree) # 子节点数量
- depth = getTreeDepth(myTree) # 深度
- firstStr = list(myTree.keys())[0] # 根节点的key
- '''X坐标=节点的x偏移量 + 叶节点数距离
- 所有该节点下子叶子节点的距离:numLeafs / plotTree.totalW
- 但是坐标在叶子节点的中心:numLeafs / 2 / plotTree.totalW
- 又因为xOff初始坐标点在原点的左边:numLeafs / 2 / plotTree.totalW + 0.5 / plotTree.totalW ,这是偏移量
- 那么x = numLeafs / 2 / plotTree.totalW + 0.5 / plotTree.totalW + plotTree.xOff
- '''
- # 根节点坐标
- # 叶子节点距离
- cntrPt = (plotTree.xOff + (1.0 + float(numLeafs)) / 2.0 / plotTree.totalw, plotTree.yOff)
- # 标记子节点属性值
- plotMidText(cntrPt, parentPt, nodeTxt)
- plotNode(firstStr, cntrPt, parentPt, decisionNode)
- secondDict = myTree[firstStr]
- plotTree.yOff = plotTree.yOff - 1.0 / plotTree.totalD
- for key in secondDict.keys():
- if type(secondDict[key]).__name__ == 'dict':
- plotTree(secondDict[key], cntrPt, str(key))
- else:
- plotTree.xOff = plotTree.xOff + 1.0 / plotTree.totalw
- plotNode(secondDict[key], (plotTree.xOff, plotTree.yOff), cntrPt, leafNode)
- plotMidText((plotTree.xOff, plotTree.yOff), cntrPt, str(key))
- plotTree.yOff = plotTree.yOff + 1.0 / plotTree.totalD
- # plot构建树
- def createPlot(inTree):
- # figure语法 创建自定义图像 定义了一个框架
- # num:图像编号或名称,数字为编号
- # facecolor:背景颜色
- fig = plt.figure(1, facecolor='white')
- #plt.close()将完全关闭图形窗口
- # plt.clf()将清除图形-您仍然可以在其上绘制另一个绘图。
- fig.clf()
- # xticks是一个列表,其中的元素就是x轴上将显示的坐标
- # yticks是y轴上显示的坐标,这里空列表则不显示坐标
- axprops = dict(xticks=[], yticks=[])
- # 这里定义一个子图窗口
- # 第一个参数xyz含义是,将框架划分为x行y列窗口,ax1代表其第z个窗口。
- # ps:111 就是一行一列第一个窗口
- # frameon = False将隐藏坐标轴
- createPlot.ax1 = plt.subplot(111, frameon=False, **axprops)
- # plotTree.totalW是决策树的叶子树,也代表宽度
- plotTree.totalw = float(getNumLeafs(inTree))
- # plotTree.totalD是决策树的深度
- plotTree.totalD = float(getTreeDepth(inTree))
- # 方便后面加上 1.0 / plotTree.totalW 后位置刚好在中间
- plotTree.xOff = -0.5 / plotTree.totalw
- plotTree.yOff = 1.0
- # 调用函数plotTree(),绘制整棵决策树,最后显示出来。
- plotTree(inTree, (0.5, 1.0), '')
- plt.show()
运行结果如下所示:
一个简单的C4.5算法,采用Python语言的更多相关文章
- 实现一个简单的邮箱地址爬虫(python)
我经常收到关于email爬虫的问题.有迹象表明那些想从网页上抓取联系方式的人对这个问题很感兴趣.在这篇文章里,我想演示一下如何使用python实现一个简单的邮箱爬虫.这个爬虫很简单,但从这个例子中你可 ...
- 实现一个简单的虚拟demo算法
假如现在你需要写一个像下面一样的表格的应用程序,这个表格可以根据不同的字段进行升序或者降序的展示. 这个应用程序看起来很简单,你可以想出好几种不同的方式来写.最容易想到的可能是,在你的 JavaScr ...
- 通过创建一个简单的骰子游戏来探究 Python
在我的这系列的第一篇文章 中, 我已经讲解如何使用 Python 创建一个简单的.基于文本的骰子游戏.这次,我将展示如何使用 Python 模块 Pygame 来创建一个图形化游戏.它将需要几篇文章才 ...
- day-7 一个简单的决策树归纳算法(ID3)python编程实现
本文介绍如何利用决策树/判定树(decision tree)中决策树归纳算法(ID3)解决机器学习中的回归问题.文中介绍基于有监督的学习方式,如何利用年龄.收入.身份.收入.信用等级等特征值来判定用户 ...
- 通过编写一个简单的漏洞扫描程序学习Python基本语句
今天开始读<Python绝技:运用Python成为顶级黑客>一书,第一章用一个小例子来讲解Python的基本语法和语句.主要学习的内容有:1. 安装第三方库.2. 变量.字符串.列表.词典 ...
- 算法课上机实验(一个简单的GUI排序算法比较程序)
(在家里的电脑上Linux Deepin截的图,屏幕大一点的话,deepin用着还挺不错的说) 这个应该是大二的算法课程上机实验时做的一个小程序,也是我的第一个GUI小程序,实现什么的都记不清了,只记 ...
- C++写一个简单的解析器(分析C语言)
该方案实现了一个分析C语言的词法分析+解析. 注意: 1.简单语法,部分秕.它可以在本文法的基础上进行扩展,此过程使用自上而下LL(1)语法. 2.自己主动能达到求First 集和 Follow 集. ...
- 【学习笔记】PYTHON语言程序设计(北理工 嵩天)
1 Python基本语法元素 1.1 程序设计基本方法 计算机发展历史上最重要的预测法则 摩尔定律:单位面积集成电路上可容纳晶体管数量约2年翻倍 cpu/gpu.内存.硬盘.电子产品价格等都遵 ...
- 一个简单的多机器人编队算法实现--PID
用PID进行领航跟随法机器人编队控制 课题2:多机器人编队控制研究对象:两轮差动的移动机器人或车式移动机器人研究内容:平坦地形,编队的保持和避障,以及避障和队形切换算法等:起伏地形,还要考虑地形情况对 ...
- 一个简单的mock server
在前后端分离的项目中, 前端无需等后端接口提供了才调试, 后端无需等第三方接口提供了才调试, 基于“契约”,可以通过mock server实现调试, 下面是一个简单的mock server,通过pyt ...
随机推荐
- 看懂java序列化,这篇就够了
前言 相信大家日常开发中,经常看到 Java 对象 "implements Serializable".那么,它到底有什么用呢?本文带你全方位的解读序列化与反序列化这一块知识点. ...
- 浅析switch和if(开发中这两者的优缺点;分析出优缺点在使用就能更确定自己需要使用哪个函数了)
分析 Switch 相较于 if 的优点 1.switch 执行效率 高于 if 的执行效率 分析: switch是在编译阶段将子函数的地址和判断条件绑定了,只要直接将a的直接映射到子函数地址去执 ...
- 即构SDK12月迭代:新增多项质量回调,互动白板、云录制SDK同步更新
即构SDK12月迭代来啦,本月LiveRoom/AudioRoom SDK新增了端到端延迟质量回调.房间会话ID信息,便于在音视频通话.直播场景中进行时延.通话质量的评测.同时还优化了硬件设备权限变更 ...
- tensorflow神经网络归一化方法
参考https://blog.csdn.net/chary8088/article/details/81542879
- Linux: rsyslog.conf 配置
refer to: https://www.debian.org/doc/manuals/debian-handbook/sect.syslog.en.html 日志子系统 Each log mess ...
- 2021-8-2 Mysql个人练习题
创建学生表 CREATE TABLE student( id int, uname VARCHAR(20), chinese FLOAT, english FLOAT, math FLOAT ); I ...
- React错误: Can't resolve 'react-dom/client'
错误截图 解决方案 当你的react版本低于18时,但仍然报这个错误,可以采用如下方案 意外的发现当我采用上述方案时,我的React路由跳转时,页面不刷新的问题也解决了,很神奇,日后技艺精进再补充.
- python: ImportError: cannot import name '_unicodefun' from 'click'
报错 报错原因 click模块版本问题 解决方案 指定click版本为8.0.4 参考链接 https://github.com/psf/black/issues/2964
- 达梦数据库: SQL查询报错《不是 GROUP BY 表达式解决方法》
报错信息: ****: 第4 行附近出现错误: 不是 GROUP BY 表达式 修改办法: 达梦可以配置兼容参数,COMPATIBLE_MODE=4,静态参数,需要重启数据库后生效! sp_set_p ...
- React请求机制优化思路
说起数据加载的机制,有一个绕不开的话题就是前端性能,很多电商门户的首页其实都会做一些垂直的定制优化,比如让请求在页面最早加载,或者在前一个页面就进行预加载等等.随着react18的发布,请求机制这一块 ...