目录

  • 一、原理
  • 二、在jupyter下实现针对西瓜数据集的ID3算法代码

一、原理

1、介绍

决策树算法是一种逼近离散函数值的方法。 它是一种典型的 分类方法 ,首先对数据进行处理,利用归纳算法生成可读的规则和决策树,然后使用决策对新数据进行分析。 本质上决策树是通过一系列规则对数据进行分类的过程。 决策树方法最早产生于上世纪60年代,到70年代末。

2、什么是决策树

决策树简单来说就是带有判决规则(if-then)的一种树,可以依据树中的判决规则来预测未知样本的类别和值。

3、定义

定义: 决策树是一个属性结构的预测模型,代表对象属性和对象值之间的一种映射关系。它由节点(node)和有向边(directed edge)组成,其节点有两种类型:内节点(internal node)和叶节点(leafnode),内部节点表示一个特征或属性,叶节点表示一个类。如上图所示的相亲例子,蓝色的椭圆内节点表示的是对象的属性,橘黄色的矩形叶节点表示分类结果(是否相亲),有向边上的值则表示对象每个属性或特征中可能取的值。

4、相关概念

(1)根结点(Root Node):它表示整个样本集合,并且该节点可以进一步划分成两个或多个子集。

(2)拆分(Splitting):表示将一个结点拆分成多个子集的过程。

(3)决策结点(Decision Node):当一个子结点进一步被拆分成多个子节点时,这个子节点就叫做决策结点。

(4)叶子结点(Leaf/Terminal Node):无法再拆分的结点被称为叶子结点。

(5)剪枝(Pruning):移除决策树中子结点的过程就叫做剪枝,跟拆分过程相反。

(6)分支/子树(Branch/Sub-Tree):一棵决策树的一部分就叫做分支或子树。

(7)父结点和子结点(Paren and Child Node):一个结点被拆分成多个子节点,这个结点就叫做父节点;其拆分后的子结点也叫做子结点。

5、信息增益

(1)熵
在信息论中,熵(entropy)是随机变量不确定性的度量,也就是熵越大,则随机变量的不确定性越大。设X是一个取有限个值得离散随机变量,其概率分布为:

则随机变量X的熵定义为:

(2)条件熵 设有随机变量(X, Y),其联合概率分布为:

条件熵H(Y|X)表示在已知随机变量X的条件下,随机变量Y的不确定性。随机变量X给定的条件下随机变量Y的条件熵H(Y|X),定义为X给定条件下Y的条件概率分布的熵对X的数学期望:

当熵和条件熵中的概率由数据估计得到时(如极大似然估计),所对应的熵与条件熵分别称为经验熵和经验条件熵。

(3)信息增益 定义:信息增益表示由于得知特征A的信息后儿时的数据集D的分类不确定性减少的程度,定义为:

Gain(D,A) = H(D) - H(D|A)

         即集合D的经验熵H(D)与特征A给定条件下D的经验条件熵H(H|A)之差。

二、在jupyter下实现针对西瓜数据集的ID3算法代码

导入西瓜数据集
import numpy as np import pandas as pd import sklearn.tree as st import math data = pd.read_csv('E:\FireFoxDownload\watermalon.txt') data

计算熵

def calcEntropy(dataSet):mD = len(dataSet)dataLabelList = [x[-1] for x in dataSet]dataLabelSet = set(dataLabelList)ent = 0for label in dataLabelSet:mDv = dataLabelList.count(label)prop = float(mDv) / mDent = ent - prop * np.math.log(prop, 2)return ent

拆分数据集

# index - 要拆分的特征的下标
# feature - 要拆分的特征
# 返回值 - dataSet中index所在特征为feature,且去掉index一列的集合
def splitDataSet(dataSet, index, feature):splitedDataSet = []mD = len(dataSet)for data in dataSet:if(data[index] == feature):sliceTmp = data[:index]sliceTmp.extend(data[index + 1:])splitedDataSet.append(sliceTmp)return splitedDataSet

选择最好的特征

# 返回值 - 最好的特征的下标
def chooseBestFeature(dataSet):entD = calcEntropy(dataSet)mD = len(dataSet)featureNumber = len(dataSet[0]) - 1maxGain = -100maxIndex = -1for i in range(featureNumber):entDCopy = entDfeatureI = [x[i] for x in dataSet]featureSet = set(featureI)for feature in featureSet:splitedDataSet = splitDataSet(dataSet, i, feature)  # 拆分数据集mDv = len(splitedDataSet)entDCopy = entDCopy - float(mDv) / mD * calcEntropy(splitedDataSet)if(maxIndex == -1):maxGain = entDCopymaxIndex = ielif(maxGain < entDCopy):maxGain = entDCopymaxIndex = ireturn maxIndex
# 返回值 - 标签
def mainLabel(labelList):labelRec = labelList[0]maxLabelCount = -1labelSet = set(labelList)for label in labelSet:if(labelList.count(label) > maxLabelCount):maxLabelCount = labelList.count(label)labelRec = labelreturn labelRec

生成树

def createFullDecisionTree(dataSet, featureNames, featureNamesSet, labelListParent):labelList = [x[-1] for x in dataSet]if(len(dataSet) == 0):return mainLabel(labelListParent)elif(len(dataSet[0]) == 1): #没有可划分的属性了return mainLabel(labelList)  #选出最多的label作为该数据集的标签elif(labelList.count(labelList[0]) == len(labelList)): # 全部都属于同一个Labelreturn labelList[0]bestFeatureIndex = chooseBestFeature(dataSet)bestFeatureName = featureNames.pop(bestFeatureIndex)myTree = {bestFeatureName: {}}featureList = featureNamesSet.pop(bestFeatureIndex)featureSet = set(featureList)for feature in featureSet:featureNamesNext = featureNames[:]featureNamesSetNext = featureNamesSet[:][:]splitedDataSet = splitDataSet(dataSet, bestFeatureIndex, feature)myTree[bestFeatureName][feature] = createFullDecisionTree(splitedDataSet, featureNamesNext, featureNamesSetNext, labelList)return myTree
# 返回值
# dataSet 数据集
# featureNames 标签
# featureNamesSet 列标签
def readWatermelonDataSet():dataSet = data.values.tolist()featureNames =['色泽', '根蒂', '敲击', '纹理', '脐部', '触感']#获取featureNamesSetfeatureNamesSet = []for i in range(len(dataSet[0]) - 1):col = [x[i] for x in dataSet]colSet = set(col)featureNamesSet.append(list(colSet))return dataSet, featureNames, featureNamesSet

绘制

# 能够显示中文
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()dataSet, featureNames, featureNamesSet=readWatermelonDataSet()
testTree= createFullDecisionTree(dataSet, featureNames, featureNamesSet,featureNames)
createPlot(testTree)

结果显示:

人工智能机器学习——西瓜决策树相关推荐

  1. 机器学习(三)西瓜决策树

    文章目录 〇. ID3决策树算法原理 1. 纯度 purity 2. 信息熵 information ertropy 3. 信息增益 information gain 4. 增益率 gain rati ...

  2. [机器学习]西瓜书南瓜书学习(更新中)

    B站网课学习视频 南瓜书datawhale开源内容 南瓜书github开源内容 什么是机器学习 概念介绍 人工智能:让机器变得像人一样拥有智能的学科 机器学习:让计算机像人一样能从数据中学习出规律的一 ...

  3. 2019年上半年收集到的人工智能机器学习方向干货文章

    2019年上半年收集到的人工智能机器学习方向干货文章 10种机器学习方法,掌握了就可以称霸朋友圈 人工智能常见算法简介 机器学习中的最优化算法总结 最萌算法学习来啦,看不懂才怪! The Next S ...

  4. 从零开始学python人工智能课程_从零开始学人工智能(12)--Python · 决策树(零)· 简介...

    原标题:从零开始学人工智能(12)--Python · 决策树(零)· 简介 感谢关注天善智能,走好数据之路↑↑↑ 欢迎关注天善智能,我们是专注于商业智能BI,人工智能AI,大数据分析与挖掘领域的垂直 ...

  5. 机器学习实战 —— 决策树(完整代码)

    声明: 此笔记是学习<机器学习实战> -- Peter Harrington 上的实例并结合西瓜书上的理论知识来完成,使用Python3 ,会与书上一些地方不一样. 机器学习实战-- 决策 ...

  6. 新一代AI人工智能机器学习研讨会即将在杭州举办,特聘叶梓老师主讲!

    新一代AI人工智能机器学习研讨会即将在杭州举办,特聘叶梓老师为本次研讨会的主讲!本次研讨会,叶梓老师将会就最前沿的人工智能技术与各位与会嘉宾进行探讨. 叶老师最新的人工智能机器学习技术培训提纲如下: ...

  7. 西瓜决策树-sklearn实现

    文章目录 sklearn实现ID3.CART算法实现 一.引包 二.读取数据 三.数据编码 四.ID3拟合 ID3算法 DecisionTreeClassifier参数说明 sklearn拟合代码 五 ...

  8. 机器学习中决策树的随机森林_决策树和随机森林在机器学习中的使用

    机器学习中决策树的随机森林 机器学习 (Machine Learning) Machine learning is an application of artificial intelligence ...

  9. 机器学习西瓜书(周志华)第七章 贝叶斯分类器

    第七章 贝叶斯分类器 1. 贝叶斯决策论 1.1 先验分布 1.2 后验分布 1.3 似然估计 1.4 四大概率在贝叶斯分类中指代含义 1. 朴素贝叶斯 7. 课后练习参考答案 1. 贝叶斯决策论 贝 ...

最新文章

  1. python 验证码识别示例(二) 复杂验证码识别
  2. 带有框架的iOS应用在设备上崩溃,dyld:库未加载,Xcode 6 Beta
  3. 基于catalog 创建RMAN存储脚本
  4. Spring boot的put请求
  5. 我三年开发经验,从字节跳动抖音离职后,看看这篇文章吧!
  6. HDOJ 2030-汉字统计
  7. Gartner:2020年数据与分析领域的十大技术趋势
  8. 手机扫描到WiFi时,WiFi站点知道吗?
  9. Tarjan点的双联通(寻找割点)
  10. CLR探索系列:深入追踪托管exe加载执行过程
  11. mysql高可用架构_MySQL高可用架构对比
  12. ANSYS Workbench网格划分具体数值方法
  13. 台式计算机虚拟内存怎么设置,电脑虚拟内存怎么设置最好 电脑虚拟内存不足怎么解决...
  14. 古时候有个【百僧问题】,一百馒头一百僧,大僧三个更无争,小僧三人分一个,大小和尚各几丁? *...
  15. tcpmux TCP 端口服务多路复用
  16. 每日一题----空瓶子喝可乐问题
  17. Windows下安装Python pyramid,并运行一个pyramid的Helloworld项目
  18. 使用turtle绘制心心相印(动态)python
  19. 差示光谱法的测定原理_金属基础知识,钢中碳含量的7种测定方法,你知道吗?...
  20. CuteQt超级群,欢迎来加

热门文章

  1. ABAP_RFC_BAPI培训教程
  2. web前端批量下载文件和图片探索
  3. 11g文档学习2----创建数据库
  4. 线程的创建与线程间通信(C语言)
  5. 关于惯性传感器的一些专业知识
  6. Android10 wifi AP功能
  7. kill -9 杀不死非僵尸的进程的处理办法
  8. jquery手写轮播图_用jQuery如何手写一个简单的轮播图?(附代码)
  9. 利用foreach循环(增强型for循环)输出二维数组的内容
  10. RTT设备和驱动(2)UART 设备