决策树实例——买计算机

一、实验内容

1. 问题描述

使用ID3算法构造出决策树。决策树也是一种二元分类方法,一个值经过相应节点的测验,要么进入真分支,要么进入假分支。所以一组值经过决策树以后,就会形成从树跟到结果节点的一条唯一路径。

2. 数据集描述

3. 实验环境(软硬件)

软件

  1. 操作系统:Windows 10
  2. IDE:Pycharm Community Edition
  3. Python环境:Conda Python3.8
  4. sklearn环境:sklearn 0.24.1

硬件

  1. CPU:11th Gen Intel(R) Core(TM) i5-11300H @ 3.10GHz 3.11 GHz
  2. RAM:16.0 GB (15.8 GB 可用)

二、算法原理

1. 名词解释

(1) “树”相关术语

  • 根节点:包含数据集中的所有数据的集合
  • 内部节点:每个内部节点为一个判断条件,并且包含数据集中满足从根节点到该节点所有条件的数据的集合。根据内部结点的判断条件测试结果,内部节点对应的数据的集合别分到两个或多个子节点中。
  • 边:那些带有文字的线段(一般使用有箭头的有向线段),线的一端连的是中间节点、另一端连的是另一个中间节点或叶节点,线段上有表示判断的文字。
  • 叶节点:叶节点为最终的类别,被包含在该叶节点的数据属于该类别。

(2)信息的度量——香农熵

集合信息的度量方式称为香农熵或者熵。熵越大数据的混乱度越高,数据越无序,相似度更低。概率p越小,熵就越大(不确定度越大),如果极端情况一件事情概率为1,它的熵就变成0了。

2. 信息增益

在划分数据集前后信息发生的变化称为信息增益,根据某一特征划分完成后多获得的信息量(消除的不确定度)。计算根据每个特征值划分的数据集获得的信息增益,获得信息增益最高的特征就是最好的选择。

信息增益是信息论中学过的互信息量,其含义是:知道某个特征A时,消除的对类别D的不确定度,或比之前多获得的信息量。

(1)计算数据集的经验熵

按两个类别分类

(2)经验条件熵

以青年为例,统计买不买的数量
P(青)P(中)P(老)P(青)\\ P(中)\\ P(老) P(青)P(中)P(老)

H(归类∣青)=I(买∣青)+I(不买∣青)H(归类∣中)=I(买∣中)+I(不买∣中)H(归类∣老)=I(买∣老)+I(不买∣老)H(归类|青)=I(买|青)+I(不买|青)\\ H(归类|中)=I(买|中)+I(不买|中)\\ H(归类|老)=I(买|老)+I(不买|老) H(归类∣青)=I(买∣青)+I(不买∣青)H(归类∣中)=I(买∣中)+I(不买∣中)H(归类∣老)=I(买∣老)+I(不买∣老)

$$ H(D|A)=H(归类|年龄)=P(青)H(归类|青)+P(中)H(归类|中)+P(老)H(归类|老) $$

(3)信息增益(互信息)

选择信息增益最大的作为下一个节点
年龄I(D,A)=H(D)−H(D∣A)收入I(D,B)=H(D)−H(D∣B)学生I(D,C)=H(D)−H(D∣C)信誉I(D,E)=H(D)−H(D∣E)年龄I(D,A)=H(D)-H(D|A)\\ 收入I(D,B)=H(D)-H(D|B)\\ 学生I(D,C)=H(D)-H(D|C)\\ 信誉I(D,E)=H(D)-H(D|E) 年龄I(D,A)=H(D)−H(D∣A)收入I(D,B)=H(D)−H(D∣B)学生I(D,C)=H(D)−H(D∣C)信誉I(D,E)=H(D)−H(D∣E)

3. ID3生成树算法

输入特征数据集,输出决策树。

  1. 取最后一列类别

    1. 判断类别是否为一类,是则直接输出即可。
    2. 如果不为一类,判断是否最后的特征(即判断特征数是否为0),是则输出实例数最大的类作为结点的类标记。
  2. 选最好的特征的索引和标签值
    1. 根据第i个特征每个取值划分数据集,计算条件熵并累加
    2. 计算第i个特征对D的信息增益
    3. 选择信息增益最大的特征作为最优特征
  3. 创建字典类型的树
  4. 根据当前最佳特征的取值,划分数据集和标签输入生成函数,返回步骤1,递归生成一条路径

三、代码分析

1. 流程图

2. 代码

用到的库

from math import log  # 香农熵用到log2
import operator

(1)数据预处理

  • 年龄:青0 中1 老2
  • 收入:高0 中1 低2
  • 学生:否0 是1
  • 信誉:良0 优1

if __name__ == '__main__':# dataSet, labels = createDataSet()raw_data = pd.read_csv('tree.csv')data = raw_data.valuesdataSet = []for d in data:d_list = d.tolist() # 数据类型arrary——>listfor i in range(d[0]):dataSet.append(d_list[1::])labels = ['信誉', '学生', '收入', '年龄']  # 特征标签featLabels = []myTree = createTree(dataSet, labels, featLabels)print(myTree)

(2)自定义函数

- 香农熵计算函数
"""
Parameters:dataSet - 数据集
Returns:shannonEnt - 经验熵(香农熵)
"""
def calcShannonEnt(dataSet):# 补充该函数 H(D)=-sum(pi*logpi)H = 0.0  # 香农熵labelCounts = {}  # 计数n = len(dataSet)  # 样本数量# 统计概率for data in dataSet:datalabel = data[n-1]  # 取类别"yes","no"if datalabel not in labelCounts.keys():labelCounts[datalabel] = 0labelCounts[datalabel] += 1# 计算熵for key in labelCounts.keys():prob = float(labelCounts[key]) / nH -= prob * log(prob, 2)  # H(D)=-sum(pi*logpi)return H
- 数据集和标签划分函数
"""
Parameters:dataSet - 待划分的数据集axis - 划分数据集的特征value - 需要返回的特征的值
Returns:无
"""# 函数说明:按照给定特征划分数据集
def splitDataSet(dataSet, axis, value):retDataSet = []for featVec in dataSet:# 每一行样本的特征向量if featVec[axis] == value: # axis维特征取值是否是这个分类reducedFeatVec = featVec[:axis]  # 该特征之前的特征reducedFeatVec.extend(featVec[axis + 1:]) # 之后的特征retDataSet.append(reducedFeatVec)return retDataSet
# 函数说明:按照给定特征的位置划分标签集
def splitLabels(labels, axis):retLabels = labels[:axis]retLabels.extend(labels[axis + 1:])return retLabels
- 选择最优特征,返回索引号
"""
Parameters:dataSet - 数据集
Returns:bestFeature - 信息增益最大的(最优)特征的索引值
"""# 函数说明:选择最优特征
def chooseBestFeatureToSplit(dataSet):numFeatures = len(dataSet[0]) - 1  # 特征的维度数baseEntropy = calcShannonEnt(dataSet) # 经验熵bestInfoGain = 0.0bestFeature = -1for i in range(numFeatures):    # 遍历所有特征(第i维)featList = [example[i] for example in dataSet]   #  获取dataSet的第i个所有特征uniqueVals = set(featList)                        #  创建set集合{},元素不可重复,set去重功能#  uniqueVals是第i维特征有多少取值newEntropy = 0.0                                 #  经验条件熵初始化# 求信息增益for value in uniqueVals:subDataSet=splitDataSet(dataSet, i, value)prob = len(subDataSet) / float(len(dataSet))    # 统计value数量,占比作为先验概率newEntropy += prob * calcShannonEnt(subDataSet)  # 条件熵infoGain = baseEntropy - newEntropy                # 信息增益print("第%d个特征的增益为%.3f" % (i, infoGain))   #打印每个特征的信息增益# 找到最大信息增益和信息增益最大的特征索引值if (infoGain > bestInfoGain):bestInfoGain = infoGainbestFeature = ireturn bestFeature   # 返回信息增益最大的特征的索引值
- 统计出现最多的类标签
"""
Parameters:classList - 类标签列表
Returns:sortedClassCount[0][0] - 出现此处最多的元素(类标签)
"""# 函数说明:统计classList中出现此处最多的元素(类标签)
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]
- 创建决策树
"""
Parameters:dataSet - 训练数据集labels - 分类属性标签featLabels - 存储选择的最优特征标签
Returns:myTree - 决策树
"""# 函数说明:创建决策树
def createTree(dataSet, labels, featLabels):print("---树---")classList = [example[-1] for example in dataSet]  # 取最后一列数值,即分类标签(是否放贷:yes or no)if classList.count(classList[0]) == len(classList):  # 如果全是一类,len(classList)统计样本个数,# #classList.count(classList[0])统计classList[0]在classList中出现的个数,如果两者相同就说明classList中只有一类# print(classList)print('---end---')return classList[0]  # 则返回当前的分类if len(dataSet[0]) == 1:  # 没剩特征了,只剩最后的分类。原来dataSet[0]是[0,0,0,0,'no']每选一个特征属性,就会删除一列# #当所有特征属性都作为结点后,就只剩下最后一列:表述“yes”或“no”return majorityCnt(classList)  # 则数分类中最大的个数进行返回bestFeat = chooseBestFeatureToSplit(dataSet)  # 选出最好的特征的索引bestFeatLabel = labels[bestFeat]  # 最好标签的值print("最好特征:", bestFeatLabel)featLabels.append(bestFeatLabel)  # 最好标签列表增加myTree = {bestFeatLabel: {}}  # 构建一棵树# del (labels[bestFeat])  # 删除这个标签???????featValues = [example[bestFeat] for example in dataSet]  # 最佳标签的一列uniqueVals = set(featValues)  # 最佳标签的值,set去重for value in uniqueVals:print("特征值:", value)myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value), splitLabels(labels,bestFeat), featLabels)return myTree

(3)输出结果

---树---
第0个特征的增益为0.045
第1个特征的增益为0.173
第2个特征的增益为0.018
第3个特征的增益为0.266
最好特征: 年龄
特征值: 0
---树---
第0个特征的增益为0.044
第1个特征的增益为0.918
第2个特征的增益为0.459
最好特征: 学生
特征值: 0
---树---
no
---end---
特征值: 1
---树---
yes
---end---
特征值: 1
---树---
yes
---end---
特征值: 2
---树---
第0个特征的增益为0.894
第1个特征的增益为0.048
第2个特征的增益为0.046
最好特征: 信誉
特征值: 0
---树---
yes
---end---
特征值: 1
---树---
第0个特征的增益为0.008
第1个特征的增益为0.008
最好特征: 学生
特征值: 0
---树---
第0个特征的增益为0.000
最好特征: 收入
特征值: yes
---树---
yes
---end---
特征值: no
---树---
no
---end---
特征值: 1
---树---
no
---end---

(4)决策树

与上一次手动推导的信息增益比较,基本一致

{‘年龄’: {0: {‘学生’: {0: ‘no’, 1: ‘yes’}}, 1: ‘yes’, 2: {‘信誉’: {0: ‘yes’, 1: {‘学生’: {0: {‘收入’: {‘no’: ‘no’, ‘yes’: ‘yes’}}, 1: ‘no’}}}}}}

3. 关键量的变化过程

数据预处理,注意类型DataFrame——>ndarray——>list

dataSet有1024个样本,每个样本除最后一维是类别外都是特征的取值

进入生成树函数
  • 分类标签列表classList

  • 选出最好特征(信息增益最大)的索引bestFeature

    经验熵:baseEntropy=0.9537113737696566

    (目前的还没有累加完的)经验条件熵:newEntropy=0.5664228731218516

    第一维特征是信誉有优良两种 ,所以特征取值范围uniqueVals={0,1}

    当前在计算信誉为良0value=0的信息增益

    查看被划分的数据集,共同点:第一维信誉特征都是良value=0,保留除信誉以外的特征

    计算信息增益infoGain,更新最大信息增益的下标(也是返回值)bestFeature

沿着最好的特征递归构建决策树

树是字典类型dict,此时最好特征是年龄 ,有老中青三种取值uniqueVals={0,1,2}

递归构建决策树

年龄0——>学生0——>no 路径结束

四、 总结

1. 遇到的问题与解决方法

(1)思考如何组织输入数据的结构?

因为createTree(dataSet, labels, featLabels)函数的参数格式均为list型,所以该实验的数据预处理需要特别注意:

  1. 数据以csv格式的文件读入raw_data = pd.read_csv('tree.csv')数据格式 DataFrame

  2. 转成ndarray格式data = raw_data.values

  3. 提取有效特征数据,并转成list格式d_list = d.tolist()

    • 每一个样本的第0维表示重复次数

    • 第一维及其以后是实际要用到的特征数据

    • 循环重复写入样本特征,每类样本重复次数为第一维的“计数”

      for i in range(d[0]): dataSet.append(d_list[1::])

  4. 标签labels = ['信誉', '学生', '收入', '年龄'] # 特征标签

(2)Debug:增加标签划分函数

决策树中一条从根节点到叶子节点的路径下,经过的标签不重复。为保证这一点上一个例子使用的方法为:每向下延申一层,就删除经历过的特征标签(如下)。

del (labels[bestFeat])  # 删除这个标签

但是在递归生成树的时候,被删掉的标签就不再出现,会影响周围路径的生成,导致超出索引范围。所以改用自己写的“标签划分函数”,其与数据集划分函数的算法原理相同:剔除当前位置的标签,之前的标签和之后的标签拼接重组。

splitLabels(labels,bestFeat)
"""
Parameters:dataSet - 待划分的标签列表axis - 划分数据集的特征下标
Returns:无
"""
def splitLabels(labels, axis):retLabels = labels[:axis]retLabels.extend(labels[axis + 1:])return retLabels

2. 知识点总结

分类器对比

  • 上周学的朴素贝叶斯分类器将概率论于数理统计的知识运用到分类中,找出输出类别Y与特征X之间的关系,即联合概率分布P(X,Y)

  • 本周所学的决策树是从信息论的角度分析如何划分数据。信息论用随机事件发生的概率来度量事件的“不确定度”,将随机事件所含有的不确定度用数学公式表示出来,集合信息的度量方式称为香农熵或者熵。决策树引入香农信息论中熵的概念。

决策树通过递归生成

  • 每一条向下延申的”树枝“,生成过程是按照数据的内在规律不断划分数据集为小的分支,直到叶子节点,则分类完毕。
  • 选择最好的划分方式,就要先选择最好的划分特征,我们希望收获的信息量越多越好,即划分之后熵越小越好,即数据越整齐越好。
    • 我们将对每个特征划分的数据集求计算一次熵,然后判断该特征是否为最好的数据集划分特征(即一个决策过程)。这里将每一个特征作为一次数据集的划分依据,然后求得划分后的数据集的熵newEntropy,当新的数据集的熵最小时,即选取该特征划分数据集前后获得最大的信息增益时,数据的混乱度降低,该特征为最好的数据集划分特征。
    • 上述数据集划分结束的标志是:每一条记录都分配到一个叶子节点,每次选取一个特征后,都将数据集划分为几个更小的数据集,我们只要对分割后的分支数据集继续使用chooseBestFeatureToSplit函数即可继续划分数据集,递归可以简单的实现这一过程。
  • 我们在实际操作中,还可以指定叶子结点的个数(即分类数,C4.5和CART算法)

3. 算法的思考

信息增益相同时如何抉择?

该例子中最后两类特征的信息增益相同应该怎么选择?此代码是选择排在前面的特征,在实际情况下这种方式是否合理?

第0个特征的增益为0.008
第1个特征的增益为0.008
过度拟合问题

比如最后一个计数为1的样本,就像是噪声数据。决策树算法增长树的每一个分支的深度,直到恰好能对训练样例比较完美地分类。实际应用中,当数据中有噪声或训练样例的数量太少以至于不能产生目标函数的有代表性的采样时,该策略可能会遇到困难。

目前是二分类问题,能否推广到多分类问题?

**时,数据的混乱度降低,该特征为最好的数据集划分特征。

  • 上述数据集划分结束的标志是:每一条记录都分配到一个叶子节点,每次选取一个特征后,都将数据集划分为几个更小的数据集,我们只要对分割后的分支数据集继续使用chooseBestFeatureToSplit函数即可继续划分数据集,递归可以简单的实现这一过程。
  • 我们在实际操作中,还可以指定叶子结点的个数(即分类数,C4.5和CART算法)

3. 算法的思考

信息增益相同时如何抉择?

该例子中最后两类特征的信息增益相同应该怎么选择?此代码是选择排在前面的特征,在实际情况下这种方式是否合理?

第0个特征的增益为0.008
第1个特征的增益为0.008
过度拟合问题

比如最后一个计数为1的样本,就像是噪声数据。决策树算法增长树的每一个分支的深度,直到恰好能对训练样例比较完美地分类。实际应用中,当数据中有噪声或训练样例的数量太少以至于不能产生目标函数的有代表性的采样时,该策略可能会遇到困难。

目前是二分类问题,能否推广到多分类问题?

【机器学习7】决策树相关推荐

  1. Scikit-Learn 机器学习笔记 -- 决策树

    Scikit-Learn 机器学习笔记 – 决策树 参考文档: handson-ml import numpy as np# 加载鸢尾花数据集 def load_dataset():from skle ...

  2. 机器学习实战-决策树-22

    机器学习实战-决策树-叶子分类 import numpy as np import pandas as pd import seaborn as sns import matplotlib.pyplo ...

  3. 利用计算机语言实现ID3算法,机器学习之决策树学习-id3算法-原理分析及c语言代码实现.pdf...

    机器学习之决策树学习-id3算法-原理分析及c语言代码实现.pdf 还剩 23页未读, 继续阅读 下载文档到电脑,马上远离加班熬夜! 亲,很抱歉,此页已超出免费预览范围啦! 如果喜欢就下载吧,价低环保 ...

  4. 【火炉炼AI】机器学习006-用决策树回归器构建房价评估模型

    [火炉炼AI]机器学习006-用决策树回归器构建房价评估模型 (本文所使用的Python库和版本号: Python 3.5, Numpy 1.14, scikit-learn 0.19, matplo ...

  5. gini系数 决策树_案例7:机器学习--使用决策树实现泰坦尼克号乘客生存率预测...

    一.决策树简介 1.1 什么是决策树? 决策树:是一种树形结构,其中每个内部节点表示一个属性上的判断,每个分支代表一个判断结果的输出,最后每个叶节点代表一种分类结果,本质是一颗由多个判断节点组成的树. ...

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

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

  7. 【机器学习】决策树(Decision Tree)

    [机器学习]k近邻算法(KNN) [机器学习]决策树(Decision Tree) [机器学习]朴素贝叶斯(Naive Bayes) 一.概述 决策树(Decision Tree)是有监督学习中的一种 ...

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

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

  9. 机器学习之决策树原理

    机器学习之决策树原理 1 决策树简介 2 数学知识 ① 信息熵 ② 条件熵 ③ 信息增益 ④ 信息增益比(信息增益率) ⑤ 基尼指数(基尼系数) 3 决策树的构建过程 4 三种决策树算法 ① ID3 ...

  10. [机器学习数据挖掘]机器学习实战决策树plotTree函数完全解析

    [机器学习&数据挖掘]机器学习实战决策树plotTree函数完全解析 http://www.cnblogs.com/fantasy01/p/4595902.html点击打开链接 import ...

最新文章

  1. linux显示不在sudoers文件中,Ubuntu无法使用sudo提权提示当前用户不在sudoers文件中...
  2. 9适应之力加多少攻击_NBA球星生涯最低分都是多少?詹皇碰上麦迪仅得3分,哈登最低1分...
  3. 设计模式:享元模式(Flyweight Pattern)
  4. 数据结构之【树形结构】复习题
  5. php系统函数代码,PHP自定义函数+系统函数库(代码示例)
  6. 【转贴】mysql导入数据load data infile用法
  7. BigDecimal 加减乘除运算
  8. Rwordseg和tmcn安装-2017.09.23
  9. Python学习笔记:交互对话环境IPython
  10. 常见数据分析误区有哪些
  11. 浅谈 JSON 那些被转义的字符们
  12. 如何C语言编程二维数组五位学生总分,C语言编程题(有关二维数组的循环的)...
  13. 火焰传感器的简单使用
  14. 我想开发一个小程序,大概需要多少钱?
  15. 软考_软件设计师_计算机组成与体系结构篇(8k字干货只为助力备考软考的你)
  16. android拖拽 字体变形,17种文字变形的创意方法
  17. Cesium3Dtilesets 使用customShader的解读以及泛光效果示例
  18. Excel如何快速查找出图片?
  19. 【小白练习】一元二次方程计算器
  20. 数学里上凹,下凹,上凸,下凸

热门文章

  1. Datawhale组队学习第五章-中值定理
  2. vsftpd匿名登陆连接报错:500 OOPS: vsftpd: refusing to run with writable root inside chroot()(未解决)
  3. AlphaTest烘焙的阴影不正确
  4. 东原地产的女性视角——对话罗韶颖
  5. 【高等数学】单射,满射,双射的区别
  6. VR全景创业必看,热门功能帮助商家顺利出圈
  7. Java在后台获取USB二维码扫描枪扫描的内容
  8. 困境下的SEO,站长如何自渡?
  9. Python 网络爬虫及数据可视化
  10. Linux打印添加水印,linux下word转pdf,加水印