当前位置: 首页 > 编程日记 > 正文

机器学习 决策树 ID3

构造决策树时需要解决的第一个问题是:当前数据集中哪个特征在划分数据分类时起决定性作用。

划分数据集的原则:将无序的数据变得更加有序

信息增益:在划分数据集前后信息发生的变化

获得信息增益最大的特征就是最好的特征

熵:信息的期望值,表示信息的混乱程序,越混乱熵越大

信息增益可以表示为信息熵的减小

[https://blog.csdn.net/moxigandashu/article/details/71305273?locationNum=9&fps=1]


以下代码均在trees.py文件内。

计算给定数据集的信息熵:

from math import log
import operator
import treePlotter
def calcShannonEnt(dataset):numEntries=len(dataset)labelCounts={}for featVec in dataset:currentLabel=featVec[-1]if currentLabel not in labelCounts.keys():labelCounts[currentLabel]=0labelCounts[currentLabel]+=1shannonEnt=0.0for key in labelCounts:     #遍历字典,key是字典的键prob=float(labelCounts[key])/numEntriesshannonEnt-=prob*log(prob,2)return shannonEnt

根据给定特征及特征值划分数据集:

def splitDataSet(dataset,index,value):  #按照给定特征划分数据集。index,value两个参数用来确定特征及其特征值retDataset=[]for featVec in dataset:if featVec[index]==value:reducedFeatVec=featVec[:index]#print(reducedFeatVec)reducedFeatVec.extend(featVec[index+1:])#print(reducedFeatVec)retDataset.append(reducedFeatVec)#print(retDataset)return retDataset
def createDataSet():dataSet=[[1,1,'yes'],[1,1,'yes'],[1,0,'no'],[0,1,'no'],[0,1,'no']]features=['no surfacing','flippers']return dataSet,features

选择最好的数据集划分方式,即为确定最恰当的特征:

def chooseBestFeatureToSplit(dataset):numFeatures=len(dataset[0])-1   #确定特征个数baseEntropy=calcShannonEnt(dataset)bestInfoGain=0bestFeature=-1for i in range(numFeatures):featureList=[example[i] for example in dataset] #第i个特征的所有特征值uniqueVals=set(featureList) #将所有特征值去重,得到标称型数值newEntropy=0.0for value in uniqueVals:subDataset=splitDataSet(dataset,i,value)prob=len(subDataset)/float(len(dataset))    #第i个特征值为value的记录个数与数据集总数的比值代表第i个特征值为value的概率newEntropy+=prob*calcShannonEnt(subDataset)infoGain=baseEntropy-newEntropy     #信息增益等于熵的减少,或者说是数据无序度的减少if infoGain>bestInfoGain:bestInfoGain=infoGainbestFeature=ireturn bestFeature

标称型数值也叫离散型,表示数值只能在有限的目标集中取得,例如true和false


构建决策树的原理:得到原始数据集,然后基于最好的属性值划分数据集,由于特征值可能多于两个,因此可能存在大于两个分支的数据集划分。第一次划分之后,数据将被向下传递到树分支的下一个节点,在这个节点上,我们可以再次划分数据。因此我们可以采用递归的原则处理数据集。

递归结束的条件是:程序遍历完所有划分数据集的属性,或者每个分支下的所有实例都具有相同的分类。如果所有实例都具有相同的分类,则得到一个叶子节点或者终止块,任何到达叶子节点的数据必然属于叶子节点的分类。

如果数据集已经处理了所有特征,剩下的记录的标签仍然不唯一,这种情况下通常采用多数表决的方法决定改叶子节点的类别:

def majorityCnt(classList): #多数表决,决定叶子节点的分类classCount={}for vote in classList:if vote not in classCount.keys():classCount[vote]=0classCount[vote]+=1sortedClassCount=sorted(classCount.items(),key=operator.itemgetter(1),reverse=True) #第二维降序排列return sortedClassCount[0][0]

递归创建树的函数代码:

def createTree(dataset,featureList):    #数据集,特征列表,产生决策树,返回值是字典featureListCopy=featureList[:]  #不能改变传递进来的实参featureListclassList=[record[-1] for record in dataset]    #标签列表,即为数据集最后一列if classList.count(classList[0])==len(classList):   #如果标签列表中第一个值出现的次数等于标签列表长度,就说明标签列表内的元素都相同了return classList[0]     #此时形成叶子节点,即为终止块if len(dataset[0])==1:  #如果数据集的第一行长度为1,说明决策树进行到使用完所有特征,只剩下标签而且标签不唯一,此时需要调用多数表决来决定此叶子节点的类别return majorityCnt(classList)bestFeat=chooseBestFeatureToSplit(dataset)  #选取最佳特征对应的索引bestFeatLabel=featureListCopy[bestFeat]     #找到最佳特征myTree={bestFeatLabel:{}}   #用字典存储决策树del featureListCopy[bestFeat]   #提出最佳特征featValues=[record[bestFeat] for record in dataset]  #最佳特征的所有取值uniqueVal=set(featValues)   #最佳特征取值形成的集合,去重for value in uniqueVal:     #value是最佳特征的值subFeatureList=featureListCopy[:]   #剔除最佳特征的特征列表myTree[bestFeatLabel][value]=createTree(splitDataSet(dataset,bestFeat,value),subFeatureList)    #splitDataSet(dataset,bestFeat,value)表示划分后的数据集return myTree

使用决策树的分类函数:

def classify(inputTree,featLabels,testVec): #参数分别是:决策树,特征列表,待分类样本firstNode=list(inputTree.keys())[0]secondDict=inputTree[firstNode]featIndex=featLabels.index(firstNode)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

使用pickle模块存储、获取决策树,避免每次使用决策树时都需要重新生成:

def storeTree(inputTree,filename):import picklefw=open(filename,'wb')  #wb表示以bytes的形式存储pickle.dump(inputTree,fw,)fw.close()
def getTree(filename):import picklefr=open(filename,'rb')  #rb表示以bytes的形式存储return pickle.load(fr)


以下代码均在treePlotter.py文件内:

使用matplotlib库的注解功能绘制树节点:

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.picture.annotate(nodeTxt,xy=parentPt,xycoords='axes fraction',xytext=centerPt,textcoords='axes fraction',va='center',ha='center',bbox=nodeType,arrowprops=arrow_args)

 获取叶节点数目:

def getNumberOfLeafs(myTree):   #计算决策树叶子节点数目numberOfLeafs=0firstNode=list(myTree.keys())[0]secondDict=myTree[firstNode]for key in secondDict.keys():if type(secondDict[key]).__name__ == 'dict':numberOfLeafs+=getNumberOfLeafs(secondDict[key])else:numberOfLeafs+=1return numberOfLeafs

 获取决策树层数:

def getTreeDepth(myTree):   #计算决策树的层数maxDepth=0firstNode=list(myTree.keys())[0]secondDic=myTree[firstNode]for key in secondDic.keys():if type(secondDic[key]).__name__=='dict':thisDepth=1+getTreeDepth(secondDic[key])  #计算此分支下的深度else:thisDepth=1if thisDepth>maxDepth:      #比较每个分支的层数与最大层数,用来更新最大层数。maxDepth=thisDepthreturn maxDepth

 plotTree函数:

def plotMidText(sonNode,parentPt,txtString): #将决策树的键值放在连接线的中间位置xMid=(parentPt[0]-sonNode[0])/2.0+sonNode[0]yMid=(parentPt[1]-sonNode[1])/2.0+sonNode[1]createPlot.picture.text(xMid,yMid,txtString)def plotTree(myTree,parentPt,nodeTxt):  #画出决策树numLeafs=getNumberOfLeafs(myTree)depth=getTreeDepth(myTree)firstNode=list(myTree.keys())[0]sonNode=(plotTree.xOff+(1.0+float(numLeafs))/2.0/plotTree.totalW,plotTree.yOff)plotMidText(sonNode, parentPt, nodeTxt)plotNode(firstNode, sonNode, parentPt, decisionNode)secondDict = myTree[firstNode]plotTree.yOff = plotTree.yOff - 1.0 / plotTree.totalDfor key in secondDict.keys():if type(secondDict[key]).__name__ == 'dict':  # test to see if the nodes are dictonaires, if not they are leaf nodesplotTree(secondDict[key], sonNode, str(key))  # recursionelse:plotTree.xOff = plotTree.xOff + 1.0 / plotTree.totalWplotNode(secondDict[key], (plotTree.xOff, plotTree.yOff), sonNode, leafNode)plotMidText((plotTree.xOff, plotTree.yOff), sonNode, str(key))plotTree.yOff = plotTree.yOff + 1.0 / plotTree.totalDdef createPlot(inTree):fig = plt.figure(1, facecolor='white')fig.clf()axprops = dict(xticks=[], yticks=[])createPlot.picture = plt.subplot(111, frameon=False, **axprops) #在函数内声明全局变量plotTree.totalW = float(getNumberOfLeafs(inTree))   #宽度plotTree.totalD = float(getTreeDepth(inTree))   #高度plotTree.xOff = -0.5 / plotTree.totalWplotTree.yOff = 1.0plotTree(inTree, (0.5, 1.0), '')plt.show()

手动声明两个决策树方便测试:

def retrieveTree(i):listOfTrees=[{'no surfacing':{0:'no',1:{'flippers':{0:'no',1:'yes'}}}},{'no surfacing':{0:'no',1:{'flippers':{0:{'head':{0:'no',1:'yes'}},1:'no'}}}}]return listOfTrees[i]


使用决策树执行具体数据的分类如下(使用决策树.py):

import trees
import treePlotterfr=open('lenses.txt')
lenses=[example.strip().split('\t') for example in fr.readlines()]
lensesLabels=['age','prescript','astigmatic','tearRate']
lensesTree=trees.createTree(lenses,lensesLabels)  #生成决策树,存储为字典
print(lensesTree)  #打印决策树字典
treePlotter.createPlot(lensesTree)  #画出决策树

 以上代码会输出决策树字典:
{'tearRate': {'reduced': 'no lenses', 'normal': {'astigamtic': {'no': {'age': {'young': 'soft', 'pre': 'soft', 'presbyopic': {'prescript': {'hyper': 'soft', 'myope': 'no lenses'}}}}, 'yes': {'prescript': {'hyper': {'age': {'young': 'hard', 'pre': 'no lenses', 'presbyopic': 'no lenses'}}, 'myope': 'hard'}}}}}}
画出决策树如下:

使用此决策树来分类:

result=trees.classify(lensesTree,lensesLabels,['young', 'myope', 'no', 'reduced'])
print(result)

 输出:

no lenses

转载于:https://www.cnblogs.com/zhhy236400/p/9846512.html

相关文章:

centos6.5原生系统修改ceph-mon 的ELF来让其加载低版本glibc库函数

文章目录Step 1:glibc-2.17 被libc.so.6库依赖&#xff0c;升级glibc库Step2:升级编译器-->4.8.2可以正常编译glibc2.17Step3:修改ELF&#xff0c;降低ceph-mon依赖的库函数版本解决ceph-mon调用高版本libc库&#xff08;修改动态库链接表ELF&#xff09;Step 1:glibc-2.17 …

如何创建一个基础jQuery插件

如何创建一个基础插件 How to Create a Basic Plugin 有时你想使一块功能性的代码在你代码的任何地方有效.比如,也许你想调用jQuery对象的一个方法,对该对象进行一系列的操作.可能你写了一个真正有用的实用函数,想它能够轻易的移植到其他项目.在这种情况下,你可能想写一个插件.…

rk3399在linux机上烧写img,烧写固件 — TB-96AI documentation

Window主机烧写固件1、安装Windows PC端USB驱动(首次烧写执行)。2、双击DriverAssitant_v4.5DriverInstall.exe打开安装程序&#xff0c;点击“驱动安装”按提示安装驱动即可&#xff0c;安装界面如下所示:3、Type-C线连接主机端的USB接口和RK3399Pro TB-96AI开发板的Type-C接口…

Eclipse,Mycclipse自动补全快捷键设置

为什么80%的码农都做不了架构师&#xff1f;>>> eclipse3.3及以后的版本中中把内容助手(content assist)的快捷键由 alt /改成了ctrl space&#xff0c;这又刚好跟我们操作系统的切换输入法的快捷键冲突&#xff0c;所以造成内容助手不能使用了&#xff0c;给写代…

php 无限极分类

无限极分类1&#xff1a; 1 public function judeg($id)2 {3 $rs Db::name(finance_class) -> field(parent_code) -> where(id,$id) -> select();4 $i 1;5 foreach($rs as $k > $v){6 if($v[parent_code] <> 0){7 $i $this -…

ceph-bluestore-tool基本使用

主要是在bluestore的实例上执行低级管理操作的使用程序,是ceph bluestore的管理工具 命令 help显示帮助信息fsck [--deep]对bluestore元数据进行一致性检查。如果指定了–deep,还要读取所有对象数据并验证校验和repair运行一致性检查 并修复我们可以发生的任何错误bluefs-expo…

Android基础是什么,Android基础概念

android {compileSdkVersion 23buildToolsVersion “23.0.1”defaultConfig {applicationId “com.example.checkyourtargetsdk"minSdkVersion 15targetSdkVersion 23versionCode 1versionName “1.0”}以上是Android工程里名称为app的module的build.gradle文件其中的内容…

HDOJ 1060 Leftmost Digit

Author Ignatius.L题目大意&#xff1a;1.第一行输入一个整数T代表接下来有T组测试数据。2.接下来的T行&#xff0c;每行输入一个整数&#xff08;1<N<1,000,000,000&#xff09;。3.输出结果为N^N&#xff08;N的N次方&#xff09;最左边的那一位数&#xff08;即最高位…

WPF-002 下拉列表的简单实现

最近在一个WPF项目中用到一个下拉列表&#xff0c;随着用户输入字符而进行显示&#xff0c;使用了绑定等知识&#xff0c;虽然实现比较简单&#xff0c;可是在性能上也是想了很多办法终于才勉强可以用&#xff0c;与大家分享下。 用于页面绑定的模型类&#xff1a; public clas…

洛谷:P3950 部落冲突

原题地址:https://www.luogu.org/problemnew/show/P3950 题目简述 给定一棵树&#xff0c;每次给定一个操作&#xff0c;有如下两种&#xff1a; 将某条边染黑 2.询问给定的u,v两点间是否有边被染黑思路 询问两点间是否有边被染黑只需要在求LCA时判一下就行。所以直接上树链剖分…

深入理解ceph-disk prepare 源码逻辑

文章目录CEPH-DISK代码逻辑DEF MAIN:DEF PARSE_ARGS:DEF Prepare.set_subparser(subparsers)def _prepare(self):PrepareBluestore的_prepare函数def prepare(self, *to_prepare_list):PrepareData类中的prepare函数def prepare_device(self, *to_prepare_list): #prepare_devi…

Deep Learning 学习随记(三)续 Softmax regression练习

上一篇讲的Softmax regression&#xff0c;当时时间不够&#xff0c;没把练习做完。这几天学车有点累&#xff0c;又特别想动动手自己写写matlab代码 所以等到了现在&#xff0c;这篇文章就当做上一篇的续吧。 回顾&#xff1a; 上一篇最后给出了softmax regression的代价函数和…

html画三个重叠的矩形,html5 实现两个矩形的叠加

Canvas Primer - Example: Drawing shadowswindow.addEventListener(load, function () {//得到canvas&#xff0c;并检测是否支持canvasvar elem document.getElementById(myCanvas);if (!elem || !elem.getContext) {return;}// 得到可以画图的上下文contextvar context el…

sqlplusw下登录sys账户

今天使用sqlplusw时&#xff0c;发现每次使用sys用户登录时总是报错&#xff0c;提示要以sysdba或者sysoper的身份登录&#xff0c;错误提示如下图所示&#xff1a;可是界面上没地方可以输入角色的地方呀&#xff0c;后经尝试发现&#xff0c;在口令输入框里首先输入密码&#…

mybatis =或这个=提示错误Tag name expecte问题解决

解决方案&#xff1a; 1、将<号或者>号进行转义 DATE_SUB(CURDATE(), INTERVAL 31 DAY) < DATE(created) 2、使用<![CDATA[ ]]>符号进行说明 <![CDATA[DATE_SUB(CURDATE(), INTERVAL 31 DAY) < DATE(created)]]> 附&#xff1a; 附录&#xff1a;常见…

s-sgdisk源码分析 “--set-alignment=value分区对齐参数”

文章目录边界对齐子命令使用源码分析sgdisk.cc main函数入口gptcl.cc DoOptions解析并执行具体命令函数gpt.cc CreatePartition创建分区函数&#xff0c;设置起始扇区对齐gpt.cc Align分区对齐函数&#xff0c;设置起始扇区对齐sgdisk命令是由 gdisk-0.8.6-4.el7.x86_64程序包安…

NuGet学习笔记(3) 搭建属于自己的NuGet服务器

文章导读 创建NuGetServer Web站点 发布站点到IIS 添加本地站点到包包数据源 在上一篇NuGet学习笔记(2) 使用图形化界面打包自己的类库 中讲解了如何打包自己的类库&#xff0c;接下来进行最重要的一步&#xff0c;从零开始搭建属于自己的NuGet服务器&#xff0c;诚然园子里及其…

计算机网络共享打不开,网络和共享中心打不开,共享无法访问没有权限

在Win7系统下如果别的计算机设置了共享&#xff0c;那么在本机设置网络发现后就可以打开网络搜索到共享计算机和共享文件了&#xff0c;不过一些朋友反馈win7系统网络发现无法启用的问题&#xff0c;下面小编整理了解决方法&#xff0c;大家可以参考一下哦。解决方法如下&#…

千万不要把 bool 当成函数参数

我们有很多 Coding Style 或 代码规范。 但这一条可能会经常被我们所遗忘&#xff0c;就是我们 经常会在函数的参数里使用bool参数&#xff0c;这会大大地降低代码的可读性。 不信&#xff1f;我们先来看看下面的代码。 当你读到下面的代码&#xff0c;你会觉得这个代码是什么意…

修改ceph-disk源码,增加指定ceph.conf部署osd的功能

文章目录 ceph环境源码修改 主文件:`ceph-disk/main.py`main函数入口parse_args(argv)增加子命令解析get_conf函数使`conf`生效修改所有调用get_conf函数的上级函数参数配置由于最近工作中需要优化osd部署流程,单节点并发加盘过程需要指定特定conf文件,来完成单盘db,wal分区…

相关计算机专业的英语文献,英文文献及翻译计算机专业.doc

英文文献及翻译计算机专业外文资料翻译—英文原文NET-BASED TASK MANAGEMENT SYSTEMHector Garcia-Molina, Jeffrey D. Ullman, Jennifer WisdomABSTRACTIn net-based collaborative design environment, design resources become more and more varied and complex. Besides c…

作业 3 应用分支与循环结构解决问题 统计字符个数

/*统计字符&#xff0c;包括空格或回车&#xff0c;数字字符和其他字符*/#include<stdio.h> int main(void) {int digit,space,letter,other; /*定义4个变量分别存放统计结果*/ char ch;int i;digitspaceletterother0; /*置…

php后期静态绑定

从php5.3开始&#xff0c;php增加了一个叫后期绑定的功能&#xff0c;用于在继承范围内引用静态调用的类 该功能从语言内部角度考虑北命名为“后期静态绑定”&#xff1b;“后期绑定”意思说&#xff1a;static&#xff1a;&#xff1a;不再被解析为定义当前方法所在的类&#…

pytest 9 pytest-datadir读取文件信息

安装&#xff1a;pip install pytest-datadir 介绍&#xff1a;用于操作测试数据目录和文件的插件。pytest-datadir他会寻找包含测试模块名字的文件夹或者全局的一个文件夹名字为data下的数据。比如以下的一个结构&#xff1a; firstdemo.py可以从test_firstdemo文件夹下的文件…

深入理解ceph-disk activate 源码逻辑

文章目录CEPH-DISK代码逻辑Activate osd的主要逻辑如下DEF main_activate激活osd的入口函数DEF mount_activate挂载临时目录&#xff0c;分配osd id并初始化osdDEF activate 分配osd_id以及初始化osdCEPH-DISK代码逻辑 本文在上文 :深入理解ceph-disk prepare 源码逻辑基础上描…

simple_html_dom meta,HTML DOM Meta content 属性

HTML DOM Meta content 属性Meta 对象定义和用法content 属性可设置或者返回 meta 元素 content 属性值。content 属性指定了 meta 信息的内容。注意&#xff1a; 这个属性可用的值依赖于name 和httpEquiv 属性的值。语法设置 content 属性&#xff1a;linkObject.content"…

struts2登录后返回登录前的页面

在Action中添加 String getUrl&#xff08;&#xff09; &#xff5b; return ServletActionContext.getRequest().getHeader("referer"); &#xff5d; 然后配置struts的这个Action的result为&#xff1a;<result type"redirect">${url}</resu…

Exchange 2010 恢复误删除的邮箱账户及其邮箱

在误删除邮箱后&#xff0c;AD中相应的账号也会随之删除&#xff0c;此时该如何恢复&#xff1f; 先来模拟邮箱被误删除&#xff0c;在EMC控制台中删除别名为jqq的邮箱 打开ADUC&#xff0c;发现相应的jqq账号也被删除了: 1.恢复AD账号 下载运行ADRecycle Bin&#xff0c;点击【…

Python 函数初识 (1)

一、今日主要内容 认识函数 函数:对功能或者动作的封装(定义) 语法: def 函数名字(形参) 函数体 函数的调用格式:函数名(实参) 函数的返回值 关键字:return 终止函数的运行 1、函数内部不写return,默认函数末尾返回…

python的popen函数

最近了解了一下python的popen函数的使用&#xff0c;主要是用来执行linux命令 函数使用 使用之前需要导入import os模块 使用方式: os.popen(cmd)返回值: 返回一个文件句柄 import os cmd"/sbin/partx /dev/sdb" result_listos.popen(cmd) print result_list执行…