数据挖掘经典十大算法_ID3算法

article/2025/10/19 22:15:42

一、ID3算法介绍

ID3算法通过自顶向下的方式构建一棵决策树来进行学习,每一次选择的是当前样本集中具有最大信息增益的属性作为测试属性。样本集根据测试属性的属性值进行划分,测试属性有多少取值就能够将样本属性划分为多少子样本集。
海洋生物数据
构建决策树:
在这里插入图片描述

二、利用python实现ID3算法

ID3.py

import math
import operator
import TreePlotter
# 1.构建西瓜数据集 离散属性
def createDataset() :# 特征列表features = ['色泽', '根蒂', '敲声', '纹理', '脐部', '触感']dataset = [# 数组中的每一个元素为一个样本共17个,属性有6个  最后一个是分类标签['青绿', '蜷缩', '浊响', '清晰', '凹陷', '硬滑', '是'],['乌黑', '蜷缩', '沉闷', '清晰', '凹陷', '硬滑', '是'],['乌黑', '蜷缩', '浊响', '清晰', '凹陷', '硬滑', '是'],['青绿', '蜷缩', '沉闷', '清晰', '凹陷', '硬滑', '是'],['浅白', '蜷缩', '浊响', '清晰', '凹陷', '硬滑', '是'],['青绿', '稍蜷', '浊响', '清晰', '稍凹', '软粘', '是'],['乌黑', '稍蜷', '浊响', '稍糊', '稍凹', '软粘', '是'],['乌黑', '稍蜷', '浊响', '清晰', '稍凹', '硬滑', '是'],['乌黑', '稍蜷', '沉闷', '稍糊', '稍凹', '硬滑', '否'],['青绿', '硬挺', '清脆', '清晰', '平坦', '软粘', '否'],['浅白', '硬挺', '清脆', '模糊', '平坦', '硬滑', '否'],['浅白', '蜷缩', '浊响', '模糊', '平坦', '软粘', '否'],['青绿', '稍蜷', '浊响', '稍糊', '凹陷', '硬滑', '否'],['浅白', '稍蜷', '沉闷', '稍糊', '凹陷', '硬滑', '否'],['乌黑', '稍蜷', '浊响', '清晰', '稍凹', '软粘', '否'],['浅白', '蜷缩', '浊响', '模糊', '平坦', '硬滑', '否'],['青绿', '蜷缩', '沉闷', '稍糊', '稍凹', '硬滑', '否']]return dataset , features # 返回数据集和特征列表'''
5.函数说明:计算给定数据集的经验熵(香农熵)
Parameters:dataSet - 数据集
Returns:shannonEnt - 经验熵(香农熵)
'''
def calcShannonEnt(dataSet) :numEntries = len(dataSet) # 计算数据中的样本数(行数)labelCount = {} # 计算每个类的样本数(每个标签出现的次数) 采用字典存放for featVec in dataSet : # 对每一组特征向量进行统计if featVec[-1] not in labelCount.keys() : # featVec[-1]提取标签信息  如果标签中没有放入统计次数的字典中,将其添加labelCount[featVec[-1]] = 0labelCount[featVec[-1]] += 1 # 计数+1shannonEnt = 0 # 设置香农熵的初始值for key in labelCount : # 计算香农熵prob = float(labelCount[key]) / numEntries # 该标签的个数/总的样本数 表示选择该标签的概率 强制转换为float类型shannonEnt -= prob * math.log(prob,2) # 利用信息熵公式 E(x) = -p(x)*logp(x) 以2为底return shannonEnt # 返回香农熵'''
6.函数说明:按照给定特征划分数据集
Parameters:dataSet - 待划分的数据集axis - 划分数据集的特征value - 需要返回的特征的值
'''
def splitDataSet(dataSet,axis,value) : # axis属性索引 value属性取值retDataSet = [] # 列表用于保存筛选出来的数据样本for featVec in dataSet : # 遍历数据集if featVec[axis] == value :reducedFeatVec = featVec[:axis] # 去掉axis特征reducedFeatVec.extend(featVec[axis + 1 :]) # 将符合条件的添加到返回的数据集中retDataSet.append(reducedFeatVec)return retDataSet # 返回划分后的数据集'''
4.函数说明:选择最优特征
Parameters:dataSet - 数据集
Returns:bestFeature - 信息增益最大的(最优)特征的索引值
'''
def chooseBestFeatureToSplit(dataSet):numFeatures = len(dataSet[0]) - 1 # -1是为了去除最后一列 保存特征数量baseEntropy = calcShannonEnt(dataSet) # 调用自定义方法计算香农熵bestInfoGain = 0.0 # 设置初始信息增益bestFeature = -1 # 设置初始最有特征的属性索引是 -1for i in range(numFeatures) : # 遍历所有的特征# 获取dataSet的第i个所有特征featList = [example[i] for example in dataSet]uniqueVals = set(featList) # 创建set集合 元素不重复newEntropy = 0 # 设置经验条件熵的初始值for value in uniqueVals : # 计算信息增益subDataSet = splitDataSet(dataSet,i,value) # splitDataSet划分后的子集prob = len(subDataSet) / float(len(dataSet)) # 计算子集的概率 划分后的子集/总的样本数量newEntropy += prob * calcShannonEnt(subDataSet) # 利用香浓熵计算经验条件熵infoGain = baseEntropy - newEntropy # 计算信息增益 香农熵-条件熵if infoGain > bestInfoGain : # 将新计算的信息增益进行比较bestInfoGain = infoGain # 更新 使得bestInfoGain中一直保存的是最大的信息增益bestFeature = i # 记录信息增益最大的特征的索引值return bestFeature # 返回信息增益最大的(最优)特征的索引值'''
3.函数说明:统计classList中出现次数最多的元素(类标签)
Parameters:classList - 类标签列表
Returns:sortedClassCount[0][0] - 出现次数最多的元素(类标签)
'''
def majorityCnt(classList) :classCount = {} # 采用字典计数for value in classList : # 遍历类标签列表 统计classList中每个元素出现的次数if value not in classCount.keys() :classCount[value] = 0classCount[value] += 1 # 计数+1sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True) # reverse=True降序排列  根据字典的值降序排序return sortedClassCount[0][0] # 返回数据最多的类别名称,由于采用降序排列,因此数组中[0][0]位置即为数据最多的类别
'''
2.函数说明:递归构建决策树
Parameters:dataSet - 训练数据集features - 分类属性标签featLabels - 存储选择的最优特征标签
Returns:myTree - 决策树
'''
def createTree(dataset,features) :# 取出样本中的所有类别标签classList = [example[-1] for example in dataset] # -1表示最后一个 是or否# 判断递归条件if classList.count(classList[0]) == len(dataset) : # 如果类别完全相同则达到递归终止条件 停止继续划分return classList[0]if len(dataset[0]) == 1 : # 遍历完所有的特征返回出现次数最多的类标签return majorityCnt(classList)bestFeat = chooseBestFeatureToSplit(dataset) # 调用自定义chooseBestFeatureToSplit方法,选择最优特征bestFeatLabel = features[bestFeat] # 获取最优特征的标签myTree = {bestFeatLabel : {}} # 根据最优特征的标签生成树 分类结果以字典的形式保存del(features[bestFeat]) # 当使用该属性完成划分后,该属性就无效了需要在features列表中将用过的属性删除featValues = [example[bestFeat] for example in dataset] # 通过for循环得到训练集中所有最有特征的属性值uniqueVals = set(featValues) # 去重操作 去掉重复的属性值for value in uniqueVals :subLabels = features[:] # 拷贝一个数据列表# 递归调用函数createTree,遍历特征,创建决策树myTree[bestFeatLabel][value] = createTree(splitDataSet(dataset,bestFeat,value),subLabels) # 对于每一个分支,需要通过递归创建树return myTreedataset,features = createDataset()
myTree = createTree(dataset,features)
print(myTree)
TreePlotter.createPlot(myTree)

TreePlotter.py

import matplotlib.pylab as plt
import matplotlib# 能够显示中文
matplotlib.rcParams['font.sans-serif'] = ['SimHei']
matplotlib.rcParams[ 'font.serif'] = ['SimHei']# 分叉节点,也就是决策节点  创建字典
decisionNode = dict(boxstyle="sawtooth", fc="0.8")# 叶子节点
leafNode = dict(boxstyle="round4", fc="0.8")# 箭头样式
arrow_args = dict(arrowstyle="<-")def plotNode(nodeTxt, centerPt, parentPt, nodeType):"""绘制一个节点:param nodeTxt: 描述该节点的文本信息:param centerPt: 文本的坐标:param parentPt: 点的坐标,这里也是指父节点的坐标:param nodeType: 节点类型,分为叶子节点和决策节点:return:"""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):"""获取叶节点的数目:param myTree::return:"""# 统计叶子节点的总数numLeafs = 0# 得到当前第一个key,也就是根节点firstStr = list(myTree.keys())[0]# 得到第一个key对应的内容secondDict = myTree[firstStr]# 递归遍历叶子节点for key in secondDict.keys():# 如果key对应的是一个字典,就递归调用if type(secondDict[key]).__name__ == 'dict':numLeafs += getNumLeafs(secondDict[key])# 不是的话,说明此时是一个叶子节点else:numLeafs += 1return numLeafsdef getTreeDepth(myTree):"""得到树的深度层数:param myTree::return:"""# 用来保存最大层数maxDepth = 0# 得到根节点firstStr = list(myTree.keys())[0]# 得到key对应的内容secondDic = myTree[firstStr]# 遍历所有子节点for key in secondDic.keys():# 如果该节点是字典,就递归调用if type(secondDic[key]).__name__ == 'dict':# 子节点的深度加1thisDepth = 1 + getTreeDepth(secondDic[key])# 说明此时是叶子节点else:thisDepth = 1# 替换最大层数if thisDepth > maxDepth:maxDepth = thisDepthreturn maxDepthdef plotMidText(cntrPt, parentPt, txtString):"""计算出父节点和子节点的中间位置,填充信息:param cntrPt: 子节点坐标:param parentPt: 父节点坐标:param txtString: 填充的文本信息:return:"""# 计算x轴的中间位置xMid = (parentPt[0] - cntrPt[0]) / 2.0 + cntrPt[0]# 计算y轴的中间位置yMid = (parentPt[1] - cntrPt[1]) / 2.0 + cntrPt[1]# 进行绘制createPlot.ax1.text(xMid, yMid, txtString)def plotTree(myTree, parentPt, nodeTxt):"""绘制出树的所有节点,递归绘制:param myTree: 树:param parentPt: 父节点的坐标:param nodeTxt: 节点的文本信息:return:"""# 计算叶子节点数numLeafs = getNumLeafs(myTree=myTree)# 计算树的深度depth = getTreeDepth(myTree=myTree)# 得到根节点的信息内容firstStr = list(myTree.keys())[0]# 计算出当前根节点在所有子节点的中间坐标,也就是当前x轴的偏移量加上计算出来的根节点的中心位置作为x轴(比如说第一次:初始的x偏移量为:-1/2W,计算出来的根节点中心位置为:(1+W)/2W,相加得到:1/2),当前y轴偏移量作为y轴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]# 计算出新的y轴偏移量,向下移动1/D,也就是下一层的绘制y轴plotTree.yOff = plotTree.yOff - 1.0 / plotTree.totalD# 循环遍历所有的keyfor key in secondDict.keys():# 如果当前的key是字典的话,代表还有子树,则递归遍历if isinstance(secondDict[key], dict):plotTree(secondDict[key], cntrPt, str(key))else:# 计算新的x轴偏移量,也就是下个叶子绘制的x轴坐标向右移动了1/WplotTree.xOff = plotTree.xOff + 1.0 / plotTree.totalW# 打开注释可以观察叶子节点的坐标变化# print((plotTree.xOff, plotTree.yOff), secondDict[key])# 绘制叶子节点plotNode(secondDict[key], (plotTree.xOff, plotTree.yOff), cntrPt, leafNode)# 绘制叶子节点和父节点的中间连线内容plotMidText((plotTree.xOff, plotTree.yOff), cntrPt, str(key))# 返回递归之前,需要将y轴的偏移量增加,向上移动1/D,也就是返回去绘制上一层的y轴plotTree.yOff = plotTree.yOff + 1.0 / plotTree.totalDdef createPlot(inTree):"""需要绘制的决策树:param inTree: 决策树字典:return:"""# 创建一个图像fig = plt.figure(1, facecolor='white')fig.clf()axprops = dict(xticks=[], yticks=[])createPlot.ax1 = plt.subplot(111, frameon=False, **axprops)# 计算出决策树的总宽度plotTree.totalW = float(getNumLeafs(inTree))# 计算出决策树的总深度plotTree.totalD = float(getTreeDepth(inTree))# 初始的x轴偏移量,也就是-1/2W,每次向右移动1/W,也就是第一个叶子节点绘制的x坐标为:1/2W,第二个:3/2W,第三个:5/2W,最后一个:(W-1)/2WplotTree.xOff = -0.5 / plotTree.totalW# 初始的y轴偏移量,每次向下或者向上移动1/DplotTree.yOff = 1.0# 调用函数进行绘制节点图像plotTree(inTree, (0.5, 1.0), '')# 绘制plt.show()if __name__ == '__main__':print((matplotlib._fname()))testTree = {'no surfacing': {0: 'no', 1: {'flippers': {0: 'no', 1: 'yes'}}, 3: 'maybe'}}createPlot(testTree)

在这里插入图片描述
在这里插入图片描述


http://chatgpt.dhexx.cn/article/7Uwfie7c.shtml

相关文章

常用数据挖掘算法

本文对数据挖掘的基础理论&#xff0c;做个框架性的总结概要&#xff0c;罗列一些通用的数据挖掘的算法和思路&#xff0c;对于自己来讲是一个回顾&#xff0c;同时也便于自己以后查阅。 频繁模式挖掘&#xff0c;关系挖掘&#xff0c;以及相互关系挖掘 所谓频繁模式挖掘&…

【数据挖掘】数据挖掘简介及十大经典算法

数据挖掘十大经典算法系列&#xff0c;点击链接直接跳转&#xff1a; 数据挖掘简介及十大经典算法&#xff08;大纲索引&#xff09; 1. 数据挖掘十大经典算法之——C4.5 算法 2. 数据挖掘十大经典算法之——K-Means 算法 3. 数据挖掘十大经典算法之——SVM 算法 4. 数据挖掘十…

数据挖掘十大经典算法 整理

数据挖掘的主要任务是分类、聚类、关联分析、预测、时序模式和偏差分析。 &#xff08;一&#xff09;C4.5 算法 C4.5算法是机器学习中的一种分类决策树算法&#xff0c;其核心是ID3 算法&#xff0c;C4.5算法继承了ID3算法的优点&#xff0c;并在以下几方面对ID3算法进行了改…

数据挖掘领域十大经典算法之—SVM算法(超详细附代码)

相关文章&#xff1a; 数据挖掘领域十大经典算法之—C4.5算法&#xff08;超详细附代码&#xff09;数据挖掘领域十大经典算法之—K-Means算法&#xff08;超详细附代码&#xff09;数据挖掘领域十大经典算法之—Apriori算法数据挖掘领域十大经典算法之—EM算法数据挖掘领域十大…

数据挖掘十大算法--Apriori算法

一、Apriori 算法概述 Apriori 算法是一种最有影响力的挖掘布尔关联规则的频繁项集的 算法&#xff0c;它是由Rakesh Agrawal 和RamakrishnanSkrikant 提出的。它使用一种称作逐层搜索的迭代方法&#xff0c;k- 项集用于探索&#xff08;k1&#xff09;- 项集。首先&#xff0c…

数据挖掘领域十大经典算法之—AdaBoost算法(超详细附代码)

相关文章&#xff1a; 数据挖掘领域十大经典算法之—C4.5算法&#xff08;超详细附代码&#xff09;数据挖掘领域十大经典算法之—K-Means算法&#xff08;超详细附代码&#xff09;数据挖掘领域十大经典算法之—SVM算法&#xff08;超详细附代码&#xff09;数据挖掘领域十大经…

数据挖掘十大经典算法(包括各自优缺点 / 适用数据场景)

本文主要分析皆来自其他资料&#xff0c;借用较为权威的总结来对我已经学习的这些经典算法做一个极为精简的概述&#xff08;根据自身经验有一定修改&#xff09;&#xff0c;另外同时附上机器学习实战中作者对各种算法的评价。另外机器学习实战这本书是本人看了这么多书籍或者…

一文弄懂数据挖掘的十大算法,数据挖掘算法原理讲解

​一个优秀的数据分析师不仅要掌握基本的统计、数据库、数据分析方法、思维、数据分析工具和技能&#xff0c;还要掌握一些数据挖掘的思路&#xff0c;帮助我们挖掘出有价值的数据&#xff0c;这也是数据分析专家和一般数据分析师的差距之一。 数据挖掘主要分为三类&#xff1a…

数据挖掘领域十大经典算法

一、什么是数据挖掘&#xff1f; 数据挖掘是人工智能和数据库领域研究的热点问题&#xff0c;所谓数据挖掘是指从数据库的大量数据中揭示出隐含的、先前未知的并有潜在价值的信息的非平凡过程。数据挖掘是一种决策支持过程&#xff0c;它主要基于人工智能、机器学习、模式识别、…

数据挖掘的10大算法

一个优秀的数据分析师,除了要掌握基本的统计学、数据库、数据分析方法、思维、数据分析工具技能之外,还需要掌握一些数据挖掘的思想,帮助我们挖掘出有价值的数据,这也是数据分析专家和一般数据分析师的差距之一。 数据挖掘主要分为分类算法,聚类算法和关联规则三大类,这…

数据挖掘十大经典算法,你都知道哪些?

当前时代大数据炙手可热&#xff0c;数据挖掘也是人人有所耳闻&#xff0c;但是关于数据挖掘更具体的算法&#xff0c;外行人了解的就少之甚少了。 数据挖掘主要分为分类算法&#xff0c;聚类算法和关联规则三大类&#xff0c;这三类基本上涵盖了目前商业市场对算法的所有需求…

Vim编辑器(二)

Vim编辑器&#xff08;二&#xff09; 一、Vim编辑器概述1、vi编辑器2、vi与Vim编辑器 二、Vim编辑器的三种模式&#xff08;重点&#xff09;1、三种模式2、三种模式之间的关系&#xff1a;3、Vim打开文件的四种方式 三、命令模式1、光标移动① 光标移动到行首与行尾② 翻屏③…

Vim编辑器使用

什么是vim? Vim 是从 vi 发展出来的一个文本编辑器。代码补全、编译及错误跳转等方便编程的功能特别丰富&#xff0c;在程序员中被广泛使用。简单的来说&#xff0c; vi 是老式的字处理器&#xff0c;不过功能已经很齐全了&#xff0c;但是还是有可以进步的地方。 vim 则可以说…

Linux之vim编辑器的使用

目录 一、vim是什么&#xff1f; 试验1&#xff1a; 二.命令模式继承用法&#xff1a; vim命令模式的快捷键: 光标移动: vim文本复制相关操作: vim文本编辑操作: 三.末行模式命令用法 部分快捷键&#xff1a; 四.vim编辑器的配置原理 一、vim是什么&#xff1f; vi…

linux之《vim编辑器》

目录 一.vim的基本概念 ​编辑 命令模式&#xff08;Normal mode&#xff09; 插入模式&#xff08;Insert mode&#xff09; 末行模式&#xff08;last line mode&#xff09; 三者的转换图 二.vim的基本操作 1. 命令模式 2. 插入模式 3. 尾行模式 三. 简单vim配置…

Linux中vi与vim编辑器

初始化的Linux虚拟机是没有vim编辑器的&#xff0c;需要手动下载安装&#xff1a; vim安装命令&#xff1a; yum -y install vim vi profile 打开文件&#xff0c;并将光标置于第8行 vi 8 profile 打开最后一行 vi profile 按n查找下一个&#xff0c;按N查找上一个 打开…

Vim编辑器使用技巧

此文章适合学生、泛linux领域开发运维人员、linux爱好者阅读&#xff0c;希望通过此文章可以帮助大家更轻松的使用vim编辑器。 vim编辑器是一个类似于Vi的著名的功能强大、高度可定制的文本编辑器&#xff0c;在Vi的基础上改进和增加了很多特性。vim是自由软件。vim普遍被推崇为…

编辑器之神——vim编辑器

编辑器之神——vim编辑器 一、vi介绍 Vi编辑器是所有Unix及Linux系统下标准的编辑器&#xff0c;类似于windows系统下的notepad&#xff08;记事本&#xff09;编辑器&#xff0c;由于在Unix及Linux系统的任何版本&#xff0c;Vi编辑器是完全相同的&#xff0c;因此可以在其他…

Linux之如何使用Vim编辑器

什么是Vim编辑器 Vim是从 vi 发展出来的一个文本编辑器。代码补完、编译及错误跳转等方便编程的功能特别丰富&#xff0c;在程序员中被广泛使用。 Linux中必须要会使用Vim&#xff08;查看内容&#xff0c;编辑内容&#xff0c;保存内容&#xff09; 简单的来说&#xff0c; …

vim编辑器详细教程

目录 一&#xff0c;第一讲 第一节&#xff1a; 移动光标 第二节 vim的进入和退出 第三节 文本编辑之删除 第四节 文本编辑之插入 第五节 文本编辑之添加 第六节 编辑文件 第一讲小结 二&#xff0c;第二讲 第一节 删除类命令 第二节 更多删除类命令 第三节 关于命令和对象…