《机器学习》西瓜书课后习题4.3——python实现基于信息熵划分的决策树算法

《机器学习》西瓜书P93

4.3 试编程实现基于信息熵进行划分选择的决策树算法,并为表4.3中数据生成一棵决策树。

以下内容是使用sklearn快捷生成的决策树,由于该函数的局限性,所得到的决策树是二叉树,但是也能做到相对正确的分类,同时在敲代码的过程中参考了大量资料和博客,在此文中一并总结了决策树构造所踩的坑和学到的东西,请大家仔细阅读

前言(都是坑、运行代码前务必阅读、理解以下部分并配置好相关的环境)

初识sklearn构造决策树

python中的sklearn库中含有DecisionTree的构造方法,在本实例中我们主要是采用该方法来构造决策树,一般方法代码量较大且复杂,如果想要详细实现决策树构建的每一步请参见其他博客。下面介绍一下python中的DecisionTree构造方法。

各种划分选择算法理论参见我的另一篇博客:https://blog.csdn.net/qq_45955883/article/details/116481131

python中sklearn库中的DecisionTreeClaasifier使用方法参见官方文档:官方文档

在python使用此类方法是ID3和CART之间存在差别,具体参见博客:

ID3、C4.5、C5.0、CART决策树区别

ID3、C4.5、CART三种决策树的区别


数据编码

注意:在使用sklearn构造决策树的过程中你会发现,该方法只针对数据部分为数值的数据集进行构造,像“色泽:青绿”这种字符串类型是无法进行处理的,因此,我们需要解决的问题是如何将这些字符串转换成数字来标识,该思路简言之就是对字符串进行编码处理。

同样地,在sklearn中也存在一部分函数用于离散型编码,对于不同的函数对应于不同的编码类型,为了降低编码这一过程对决策树的产生所造成的影响最低,同时也要考虑最终输出结果能够清晰明了,那么我们究竟该选择哪一种编码方式对我们的数据进行合适的编码呐?

关于sklearn中的多种离散型编码方式,参见博客:sklearn中多种编码方式——category_encoders(one-hot多种用法)

经过最终的比较和分析,我们选定使用DictVectorizer方法来对数据中的离散型内容进行编码,同时使用preprocessing.LabelBinarizer对标记进行编码,原因如下

  1. 使用preprocessing.LabelBinarizer对标记进行编码很容易理解,就是将标签进行二值化,即’1’代表’是‘,’0‘代表‘否’。从而将字符转换为0-1表示。

  2. DictVectorizer的处理对象是符号化(非数字化)的但是具有一定结构的特征数据,如字典等,将符号转成数字0/1表示。这句话是什么意思呐?下面看一个例子就能明白

    #-*- coding:utf-8 -*-#学习目标:使用DictVectorizer对使用字典存储的数据进行特征抽取和向量化#定义一组字典列表,用来表示多个数据样本(每个字典代表一个数据样本)
    measurements = [{'city':'Beijing','temperature':33.},{'city':'London','temperature':12.},{'city':'San Fransisco','temperature':18.}]
    #从sklearn.feature_extraction导入DictVectorizer
    from sklearn.feature_extraction import DictVectorizer
    vec = DictVectorizer()
    #输出转化后的特征矩阵
    print vec.fit_transform(measurements).toarray()
    #输出各个维度的特征含义
    print vec.get_feature_names()
    

    输出结果为:

    [[  1.   0.   0.  33.][  0.   1.   0.  12.][  0.   0.   1.  18.]]
    
    ['city=Dubai', 'city=London', 'city=San Fransisco', 'temperature']
    

    我们不难发现,DictVectorizer对非数字化的处理方式是,借助原特征的名称,组合成新的特征,并采用0/1的方式进行量化,而数值型的特征转化比较方便,一般情况维持原值即可。

    其中[ 1. 0. 0. 33.]代表的含义是’city=Dubai,temperature=33’,因为数组第一个元素为1,故表示‘city=Dubai’被选中,最后的元素代表‘temperature’的具体的值;该方法只针对离散型的值进行编码,对原本为数值的不修改值。

    那么对于我们的西瓜数据集2.0为什么适用于这种方法呐?

    首先,我们的数据集中‘密度’和‘含糖率’是连续的,其他属性是离散的,因此使用上述方法可以统一进行一次性编码,无需分开编码后再合并。

    第二,该方法中的离散型数据均使用0-1来表示,就好像线性模型中的对率回归中使用的“单位阶跃函数”一样,对于x>0.5,可认为x=1,而x<0.5代表x=0,虽然表面看似是连续性的数值,实际其离散的特性已经隐含其中,并未因编码而对数据原本的特性产生较大的影响。

接下来我们来谈一谈决策树的可视化问题……


决策树的可视化

同样的,python中也提供了决策树可视化的库和函数,即Graphviz,我们只需要在决策树建立完成之后将其导出到graphviz,

可视化软件gvedit.exe 免费下载地址:graphviz-2.38.msi免费下载

运行程序后会产生一个dot文件,使用gvedit.exe打开即可,注意:由于我的程序的问题最终产生的dot文件中文无法正确输出,需要以txt文本打开后在文本中添加多行命令:fontname=“SimSun”,添加到节点内,具体的操作百度搜索一下就知道了……


综上,我们大致可以得到编程的主要思路,读取数据后使用二值化进行编码,将字符串类型的数据编码为0、1,而数字型数据保持float类型不做改变,然后利用sklearn建立决策树,完成之后利用graphviz进行可视化输出即可。

下面给出每一步实现的程序代码,并在个别代码附加详细解释和说明……

  • 数据集——西瓜数据集3.0.csv(我们csv文件的编码类型是GBK,在使用文件读取数据的时候注意下!)

    编号,色泽,根蒂,敲声,纹理,脐部,触感,密度,含糖率,好瓜
    1,青绿,蜷缩,浊响,清晰,凹陷,硬滑,0.697,0.46,是
    2,乌黑,蜷缩,沉闷,清晰,凹陷,硬滑,0.774,0.376,是
    3,乌黑,蜷缩,浊响,清晰,凹陷,硬滑,0.634,0.264,是
    4,青绿,蜷缩,沉闷,清晰,凹陷,硬滑,0.608,0.318,是
    5,浅白,蜷缩,浊响,清晰,凹陷,硬滑,0.556,0.215,是
    6,青绿,稍蜷,浊响,清晰,稍凹,软粘,0.403,0.237,是
    7,乌黑,稍蜷,浊响,稍糊,稍凹,软粘,0.481,0.149,是
    8,乌黑,稍蜷,浊响,清晰,稍凹,硬滑,0.437,0.211,是
    9,乌黑,稍蜷,沉闷,稍糊,稍凹,硬滑,0.666,0.091,否
    10,青绿,硬挺,清脆,清晰,平坦,软粘,0.243,0.267,否
    11,浅白,硬挺,清脆,模糊,平坦,硬滑,0.245,0.057,否
    12,浅白,蜷缩,浊响,模糊,平坦,软粘,0.343,0.099,否
    13,青绿,稍蜷,浊响,稍糊,凹陷,硬滑,0.639,0.161,否
    14,浅白,稍蜷,沉闷,稍糊,凹陷,硬滑,0.657,0.198,否
    15,乌黑,稍蜷,浊响,清晰,稍凹,软粘,0.36,0.37,否
    16,浅白,蜷缩,浊响,模糊,平坦,硬滑,0.593,0.042,否
    17,青绿,蜷缩,沉闷,稍糊,稍凹,硬滑,0.719,0.103,否
    
  • 主要代码块

    1. 建立一个函数is_number,作用是将数据中的字符型数字转换为float类型。

      def is_number(n):is_number = Truetry:num = float(n)# 检查 "nan"is_number = num == num   # 或者使用 `math.isnan(num)`except ValueError:is_number = Falsereturn is_number
      
    2. 建立一个函数用于读取数据,并将数据进行预处理

      def loadData(filename):data=open(filename,'r',encoding='GBK')reader = csv.reader(data)headers = next(reader)featureList = []labelList = []for row in reader:labelList.append(row[len(row)-1])rowDict = {}for i in range(1,len(row)-1):if is_number(row[i]) == True:rowDict[headers[i]] = float(row[i])else:rowDict[headers[i]]=row[i]featureList.append(rowDict)print(featureList)print(labelList)return featureList,labelList
      
    3. 构造决策树并进行可视化输出

      def createDTree(featureList,labelList):vec = DictVectorizer()dummyX = vec.fit_transform(featureList).toarray()# print("dummyX:"+str(dummyX))# print(vec.get_feature_names())# print("labelList:"+str(labelList))lb = preprocessing.LabelBinarizer()dummyY = lb.fit_transform(labelList)# print("dummyY: ",str(dummyY))clf = tree.DecisionTreeClassifier(criterion='gini')clf = clf.fit(dummyX,dummyY)print("clf: ",str(clf))print(vec.get_feature_names())print(dummyX)print(dummyY)target_name=['不是好瓜','是好瓜']with open("DecisionTree_gini.dot",'w') as f:f = tree.export_graphviz(clf,feature_names=vec.get_feature_names(),class_names=target_name,out_file=f)
      
    4. 外部调用函数

      filename='西瓜数据集3.0.csv'
      featureList,labelList=loadData(filename)
      createDTree(featureList,labelList)
      
  • 决策树可视化展示

    1. 基于基尼指数建立的决策树

  1. 基于基尼指数建立的决策树2

  2. 基于信息增益建立的决策树

针上面生成的决策树图像的几点说明:

  1. 基于基尼指数生成的决策树有两种,why?参见博客:sklearn 决策树相同数据集及模型参数为什么生成的模型不一样?
  2. 图的阅读方法,以第一幅图为例现予以解释:第一个节点中的samples=17,说明此时样本个数为17个,gini=0.498代表基尼指数,根据”含糖率<=0.204“分为小于0.204 和大于0.204两个分支;对于第二个节点”触感=硬滑<=0.5"是什么意思呢?我们最初在进行编码的时候设置的自己具有的属性值为1,不具有的为0,即如果该样本”触感=硬滑“则对应的值为1,否则为0,那么”触感=硬滑<=0.5"的意思是”触感=硬滑“这一属性值为0(x小于0.5,x=0),即触感不硬滑;如果为True(代表触感不硬滑)则分到“色泽=乌黑<=0.5”这一节点,如果为False(代表触感硬滑)则分到“不是好瓜”这一节点。

【完整源代码】

'''
4.3 试编程实现基于信息熵进行划分选择的决策树算法,并为表4.3中数据生成一棵决策树
'''import csv
from sklearn.feature_extraction import DictVectorizer
from sklearn import preprocessing
from sklearn import treedef is_number(n):is_number = Truetry:num = float(n)# 检查 "nan"is_number = num == num   # 或者使用 `math.isnan(num)`except ValueError:is_number = Falsereturn is_numberdef loadData(filename):data=open(filename,'r',encoding='GBK')reader = csv.reader(data)headers = next(reader)featureList = []labelList = []for row in reader:labelList.append(row[len(row)-1])rowDict = {}for i in range(1,len(row)-1):if is_number(row[i]) == True:rowDict[headers[i]] = float(row[i])else:rowDict[headers[i]]=row[i]featureList.append(rowDict)print(featureList)print(labelList)return featureList,labelListdef createDTree(featureList,labelList):vec = DictVectorizer()dummyX = vec.fit_transform(featureList).toarray()# print("dummyX:"+str(dummyX))# print(vec.get_feature_names())# print("labelList:"+str(labelList))lb = preprocessing.LabelBinarizer()dummyY = lb.fit_transform(labelList)# print("dummyY: ",str(dummyY))clf = tree.DecisionTreeClassifier(criterion='gini')clf = clf.fit(dummyX,dummyY)print("clf: ",str(clf))print(vec.get_feature_names())print(dummyX)print(dummyY)target_name=['不是好瓜','是好瓜']with open("DecisionTree_gini.dot",'w') as f:f = tree.export_graphviz(clf,feature_names=vec.get_feature_names(),class_names=target_name,out_file=f)filename='西瓜数据集3.0.csv'
featureList,labelList=loadData(filename)
createDTree(featureList,labelList)

后记

内容较多代码若有错误请及时留言联系,可能上述代码并不符合题目上要求使用的方法,鉴于代码复杂度和任务量故选择此类简单快速实现的方法来构造决策树,如有任何问题欢迎留言讨论交流!!!

《机器学习》西瓜书课后习题4.3——python实现基于信息熵划分的决策树算法(简单、全面)相关推荐

  1. 《机器学习》西瓜书课后习题9.4——python实现K-means算法

    <机器学习>西瓜书课后习题9.4--python实现K-means算法 9.4 试编程实现k均值算法,设置三组不同的k值.三组不同的初始中心点,在西瓜数据集4.0上进行实验比较, 并讨论什 ...

  2. 机器学习(周志华)西瓜书 课后习题4.3 信息熵决策树算法——python实现(包括树的可视化)

    机器学习(周志华)西瓜书 课后习题4.3 信息熵决策树算法--python实现(包括树的可视化) 算法原理 1.信息熵 2.信息增益 我们所以要做的就是不断地从当前剩余的属性当中选取最佳属性对样本集进 ...

  3. 《机器学习》西瓜书课后习题作业笔记

    仅以此纪念我大学最后一门也可能是对我读研最有用的一门选修课. 目录 目录 目录 前言 第一章 绪论 T1.1 T1.2 第二章 模型评估与选择 T2.1 T2.2 T2.3 T2.4 第三章 线性模型 ...

  4. 周志华西瓜书课后习题答案总目录

    https://blog.csdn.net/icefire_tyh/article/details/52064910 机器学习(周志华西瓜书)参考答案总目录 从刚开始学习机器学习到现在也有几个月了,期 ...

  5. 周志华《机器学习》习题4.4——python实现基于信息熵进行划分选择的决策树算法

    1.题目 试编程实现基于信息熵进行话饭选择的决策树算法,并为表4.3中数据生成一棵决策树. 表4.3如下: 另外再附个txt版的,下次可以复制粘贴: 青绿,蜷缩,浊响,清晰,凹陷,硬滑,0.697,0 ...

  6. 西瓜书 课后习题6.3 SVM,bpa神经网络,ID3决策树 比较

    import csv from sklearn import svm import numpy as np from math import log import operatordef dataSe ...

  7. 周志华-机器学习西瓜书-第三章习题3.3 编程实现对率回归

    本文为周志华机器学习西瓜书第三章课后习题3.3答案,编程实现对率回归,数据集为书本第89页的数据 使用tensorflow实现过程 # coding=utf-8 import tensorflow a ...

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

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

  9. 小白学机器学习西瓜书-第三章对数几率回归

    小白学机器学习西瓜书-第三章对数几率回归 3.3 对数几率回归 3.3.1 对数几率函数 3.3.1 估计参数 上一部分我们介绍了线性回归,包括简单的二元回归和多元回归,这两个主要解决的是拟合预测的问 ...

最新文章

  1. 利用smarty生成静态页的关键代码
  2. keil debug如何在watch直接修改变量值_printf系列教程03_SWO打印输出配置,基于Keil『Debug(printf)Viewer』...
  3. yum 的 group的信息
  4. 关于线程池ThreadPoolExecutor使用总结
  5. Kali-Linux-2019.04虚拟机与物理机实现复制粘贴功能
  6. forEach for 循环
  7. cartographer探秘第四章之代码解析(六) --- 后端优化 --- 优化求解
  8. 51nod1298--圆与三角形
  9. 预知昨天事情不顺,果然碰到两个
  10. Thinkphp 6.0商城系统,B2C商城系统全新UI
  11. 谷歌FLASH无法添加保存网站
  12. Photoshop2020默认快捷键整理(Mac版)
  13. 各类排序算法比较分析
  14. 服务器封包协议号,DHCP协议的租约确认和封包格式
  15. 本田及通用公司利用区块链技术探索智能电网与电动汽车的互操作性
  16. 爬虫--爬取单张图片
  17. c语言定义禁止优化变量,c语言防止优化
  18. SQL Server 学习5(随机数,整数,编号,序号)
  19. 自考学历和成考学历哪个更高一些 有啥区别
  20. 2022飞鱼科技--鱼苗夏令营实习--游戏客户端--一面(已挂)

热门文章

  1. 信息系统项目管理师论文-项目整体管理
  2. web of science 中批量导出文件ciw到endnote时,没反应怎么操作
  3. 使用了非标准扩展_标准溶液的正确使用
  4. 江南爱软装十大品牌 软装包括什么
  5. 向mycat中插入数据的时候,一定要将字段写完整
  6. Linux内核:源代码
  7. 《海外社交媒体营销》一一1.5 小结
  8. 无法上网故障排查过程及复现过程系ip冲突造成
  9. reverse()反转函数
  10. 2023全国特种作业操作证高压电工试卷一[安考星]