机器学习 - 使用 ID3 算法从原理到实际举例理解决策树

一、什么是决策树

1.基本概念

决策树是一种树形结构,由结点(node)有向边(directed edge) 组成。其中结点分为两类:

  • 内部结点(internal node):表示一个属性(特征)
  • 叶结点(leaf node):表示一个类别

决策树是常用的分类机器学习方法。

2.实际举例说明

以 “相亲对象分类系统” 为例构建简单决策树:

  • 内部结点(长方形):特征 “有无房子”“有无上进心”
  • 叶结点(椭圆形):类别 “值得考虑”“备胎”“Say Goodbye”
  • 分类逻辑:
  • 相亲对象有房子→划分为 “值得认真考虑”
  • 没有房子但有上进心→划分为 “备胎”既没有房子也没有上进心→划分为 “Say Goodbye

实际分类中存在多个特征量,可构建多种决策树,核心问题是如何筛选出最优决策树

二、介绍建立决策树的算法

决策树算法的核心差异在于特征选择指标,常见算法对比如下:

算法

特征选择指标

核心逻辑

ID3

信息增益

信息增益越大,特征对降低数据不确定性的能力越强,优先作为上层结点

C4.5

信息增益率

解决 ID3 对多值特征的偏好问题,通过 “增益率 = 信息增益 / 特征固有值” 平衡选择

CART

基尼指数

基尼指数越小,数据纯度越高,优先选择使基尼指数下降最多的特征

本文重点讲解ID3 算法,以下是其核心概念与公式:

1. 某个分类的信息

单个分类的信息表示该分类的不确定性,公式为:

其中,P(x_i) 是选择该分类的概率。

2. 熵(Entropy)

熵是随机变量不确定性的度量,定义为信息的期望值,公式为:

其中,n 是分类的数目;熵值越大,数据不确定性越高。

3. 经验熵(Empirical Entropy)

4. 条件熵(Conditional Entropy)

已知随机变量 X 的条件下,随机变量 Y 的不确定性,公式为:

其中,p_i 是 X=x_i 的概率,H(Y|X=x_i) 是 X=x_i 时 Y 的熵。

5. 信息增益(Information Gain)

样本集 D 的经验熵 H(D) 与特征 A 给定条件下 D 的经验条件熵 H(D|A) 之差,公式为:

关键结论:特征的信息增益值越大,该特征对分类的贡献越强,应优先作为决策树的上层结点。

三、决策树的一般流程

决策树构建分为 6 个步骤,适用于各类决策树算法:

  1. 收集数据:通过爬虫、问卷、数据库查询等方式获取原始数据,无固定方法。
  1. 准备数据:树构造算法仅支持标称型数据(离散类别数据),需将数值型数据离散化(如将 “年龄 20-30” 划分为 “青年”)。
  1. 分析数据:构建树后,通过可视化、误差分析等方式验证树结构是否符合预期。
  1. 训练算法:根据特征选择指标(如 ID3 的信息增益),递归构建决策树的数据结构。
  1. 测试算法:使用测试集计算决策树的错误率,评估模型性能。
  1. 使用算法:将训练好的决策树应用于实际场景(如贷款审批、客户分类),并持续迭代优化。

四、实际举例构建决策树

以 “贷款申请分类” 为例,使用 ID3 算法构建决策树。

1. 数据集准备

贷款申请样本数据表(原始)

ID

年龄

有工作

有自己的房子

信贷情况

类别(是否给贷款)

1

青年

一般

2

青年

3

青年

4

青年

一般

5

青年

一般

6

中年

一般

7

中年

8

中年

9

中年

非常好

10

中年

非常好

11

老年

非常好

12

老年

13

老年

14

老年

非常好

15

老年

一般

数据编码(标称化处理)
  • 年龄:0 = 青年,1 = 中年,2 = 老年
  • 有工作:0 = 否,1 = 是
  • 有自己的房子:0 = 否,1 = 是
  • 信贷情况:0 = 一般,1 = 好,2 = 非常好
  • 类别:no = 否,yes = 是
数据集代码定义
from math import log
def createDataSet():dataSet = [[0, 0, 0, 0, 'no'],    # 样本1[0, 0, 0, 1, 'no'],    # 样本2[0, 1, 0, 1, 'yes'],   # 样本3[0, 1, 1, 0, 'yes'],   # 样本4[0, 0, 0, 0, 'no'],    # 样本5[1, 0, 0, 0, 'no'],    # 样本6[1, 0, 0, 1, 'no'],    # 样本7[1, 1, 1, 1, 'yes'],   # 样本8[1, 0, 1, 2, 'yes'],   # 样本9[1, 0, 1, 2, 'yes'],   # 样本10[2, 0, 1, 2, 'yes'],   # 样本11[2, 0, 1, 1, 'yes'],   # 样本12[2, 1, 0, 1, 'yes'],   # 样本13[2, 1, 0, 2, 'yes'],   # 样本14[2, 0, 0, 0, 'no']     # 样本15]labels = ['年龄', '有工作', '有自己的房子', '信贷情况']  # 特征标签labels1 = ['放贷', '不放贷']  # 分类标签return dataSet, labels, labels1  # 返回数据集、特征标签、分类标签

2. 计算经验熵 H (D)

数学计算

样本集 D 共 15 个样本,其中 “放贷(yes)”9 个,“不放贷(no)”6 个,经验熵为:

代码实现
def calcShannonEnt(dataSet):numEntires = len(dataSet)  # 数据集行数(样本数)labelCounts = {}  # 存储每个标签的出现次数for featVec in dataSet:currentLabel = featVec[-1]  # 提取最后一列(分类标签)if currentLabel not in labelCounts.keys():labelCounts[currentLabel] = 0labelCounts[currentLabel] += 1  # 标签计数shannonEnt = 0.0  # 初始化经验熵for key in labelCounts:prob = float(labelCounts[key]) / numEntires  # 标签出现概率shannonEnt -= prob * log(prob, 2)  # 计算经验熵return shannonEnt# 测试代码
if __name__ == '__main__':dataSet, features, labels1 = createDataSet()print("数据集:", dataSet)print("经验熵H(D):", calcShannonEnt(dataSet))  # 输出:0.9709505944546686

3. 计算信息增益(选择最优特征)

数学计算(以 “有自己的房子” 为例)

设特征 A_3(有自己的房子),取值为 “是(1)” 和 “否(0)”:

  • 子集 D_1(A_3=1):共 9 个样本,均为 “yes”,经验熵 H(D_1)=0
  • 子集 D_2(A_3=0):共 6 个样本,“yes” 3 个、“no” 3 个
  • 经验熵 
  • 条件熵 
  • 信息增益 (注:原文计算结果为 0.420,此处以原文代码输出为准)

其他特征的信息增益计算结果:

  • 年龄(A_1):0.083
  • 有工作(A_2):0.324
  • 信贷情况(A_4):0.363

结论:特征 “有自己的房子(A_3)” 信息增益最大,作为决策树的根节点。

代码实现
"""
函数:按照给定特征划分数据集
参数:dataSet - 待划分数据集axis - 特征索引value - 特征取值
返回:retDataSet - 划分后的子集
"""
def splitDataSet(dataSet, axis, value):retDataSet = []for featVec in dataSet:if featVec[axis] == value:reducedFeatVec = featVec[:axis]  # 去掉当前特征列reducedFeatVec.extend(featVec[axis+1:])  # 拼接剩余列retDataSet.append(reducedFeatVec)return retDataSet"""
函数:选择最优特征
参数:dataSet - 数据集
返回:bestFeature - 最优特征索引
"""
def chooseBestFeatureToSplit(dataSet):numFeatures = len(dataSet[0]) - 1  # 特征数量(减去分类列)baseEntropy = calcShannonEnt(dataSet)  # 基础经验熵bestInfoGain = 0.0  # 最优信息增益bestFeature = -1  # 最优特征索引for i in range(numFeatures):featList = [example[i] for example in dataSet]  # 提取第i列特征uniqueVals = set(featList)  # 特征的唯一取值newEntropy = 0.0  # 条件熵for value in uniqueVals:subDataSet = splitDataSet(dataSet, i, value)  # 划分子集prob = len(subDataSet) / float(len(dataSet))  # 子集概率newEntropy += prob * calcShannonEnt(subDataSet)  # 累加条件熵infoGain = baseEntropy - newEntropy  # 计算信息增益print(f"第{i}个特征({labels[i]})的增益为:{infoGain:.3f}")if infoGain > bestInfoGain:bestInfoGain = infoGainbestFeature = ireturn bestFeature# 测试代码
if __name__ == '__main__':dataSet, labels, labels1 = createDataSet()bestFeature = chooseBestFeatureToSplit(dataSet)print(f"最优特征索引值:{bestFeature}(对应特征:{labels[bestFeature]})")# 输出:最优特征索引值:2(对应特征:有自己的房子)

4. 生成决策树(递归构建)

核心逻辑
  1. 若样本集所有样本属于同一类别,直接返回该类别(叶节点);
  2. 若无特征可划分或样本特征全相同,返回出现次数最多的类别(叶节点);
  3. 选择最优特征作为当前节点,按特征取值划分子集;
  4. 对每个子集递归执行上述步骤,生成子树。
代码实现
import operator"""
函数:统计出现次数最多的类别
参数:classList - 类别列表
返回:sortedClassCount[0][0] - 最多类别
"""
def majorityCnt(classList):classCount = {}for vote in classList:if vote not in classCount.keys():classCount[vote] = 0classCount[vote] += 1# 按类别次数降序排序sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)return sortedClassCount[0][0]"""
函数:创建决策树
参数:dataSet - 训练集labels - 特征标签featLabels - 存储选择的最优特征
返回:myTree - 决策树(字典结构)
"""
def createTree(dataSet, labels, featLabels):classList = [example[-1] for example in dataSet]  # 提取所有类别# 情况1:所有样本类别相同if classList.count(classList[0]) == len(classList):return classList[0]# 情况2:无特征可划分或特征全相同if len(dataSet[0]) == 1 or len(labels) == 0:return majorityCnt(classList)# 情况3:递归构建树bestFeat = chooseBestFeatureToSplit(dataSet)  # 最优特征索引bestFeatLabel = labels[bestFeat]  # 最优特征标签featLabels.append(bestFeatLabel)myTree = {bestFeatLabel: {}}  # 决策树字典del(labels[bestFeat])  # 删除已使用的特征标签featValues = [example[bestFeat] for example in dataSet]  # 最优特征的所有取值uniqueVals = set(featValues)  # 唯一取值for value in uniqueVals:subLabels = labels[:]  # 复制特征标签(避免递归修改原列表)# 递归生成子树myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value), subLabels, featLabels)return myTree# 测试代码
if __name__ == '__main__':dataSet, labels, labels

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/96098.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/96098.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【期末复习】嵌入式——S5PV210开发板

本文为嵌入式课程期末复习,仅供参考,所用课本:嵌入式Linux操作系统(李建祥著)。第一章1.1 简述嵌入式微处理器数据存储格式的大,小端模式。大端模式是指数据的高字节保存在内存的低地址中,而数据…

word文档结尾批量插入图片 docx批量插入图片 指定几张

如果你有一些word文档。比如工作总结。你想每一个文档里面都插入几张图片。插入到每个文档的结尾,那么你可以使用这个工具。首先准备好你的文档。然后把它们拖进右边的方框中。拖动的时候,拖动第一个,然后准备好你的图片。把你的图片全部拖动…

CodeBuddy国际版又更新了体验感1

CodeBuddy国际版又更新了 更好的使用体验更少的资源消耗合理的消耗剩余资源使用起来也是很不错的,这次更新自动模式想不到的少,可以用于其他的例如翻译与写测试用例或者其他的说明文档等或者是阅读一下项目更好了解项目总的上来说 使用体验响应速度还是不…

基于开源AI智能名片链动2+1模式S2B2C商城小程序的公益课引流策略研究

摘要:本文聚焦公益课引流场景,探讨开源AI智能名片、链动21模式与S2B2C商城小程序的融合应用。通过构建低成本用户裂变体系,分析该技术组合在精准筛选、社群运营、激励机制设计中的协同效应。研究提出"智能名片画像-链动裂变激励-S2B2C生…

季度最强策略:年化247%,回撤10%,夏普比率3.79。附大小盘轮动策略python源代码。

原创内容第993篇,专注AGI,AI量化投资、个人成长与财富自由。 季度最强策略: 年化247%,回撤10%,夏普比率3.79。3积分可查看参数。 大小盘轮动的策略源代码: 年化收益18.8%。 from engine import Task, Eng…

testng.xml

一、TestNG.xml 是 TestNG 测试框架的核心配置文件,用于组织和控制测试执行。通过它,可以灵活地管理测试套件、测试类、方法,并设置各种执行参数一个基本的 testng.xml文件通常以 ​​DOCTYPE 声明​​开头,并遵循特定的文档类型定…

上架商品合规流程有多条,有的长,有的短,有的需要审核,校验商品的合规性

博主介绍:✌全网粉丝5W,全栈开发工程师,从事多年软件开发,在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战,博主也曾写过优秀论文,查重率极低,在这方面有丰富的经验…

[嵌入式][stm32h743iit6] 野火繁星stm32h743iit6开发板使用学习记录

[嵌入式][stm32h743iit6] 野火繁星stm32h743iit6开发板使用学习记录野火繁星STM32H743IIT6开发板使用学习速记问题描述尝试解决野火繁星STM32H743IIT6开发板使用学习速记 问题描述 在使用该开发板学习stm32hal库pwm开发时, 偶遇代码无法驱动sg90舵机进行旋转, 无论占空比设置…

Android 热点开发的相关api总结

Android 热点 一、前言热点开发属于系统级功能开发,涉及的核心 API 多为系统签名权限保护(如android.permission.TETHER_PRIVILEGED),通常仅系统应用(如 Settings)可正常调用。 实际开发中,除基…

Claude Code 使用指南

Claude Code 使用指南 在 AI 辅助编程领域,我们正经历从简单的代码补全到能够自主执行复杂任务的“智能体”(Agent)的深刻变革。Claude Code 正是这一变革的杰出代表。它并非一个简单的问答机器人,而是一个设计精密的编程协作系统…

Spring Boot常用注解-详细解析+示例

1. SpringBootApplication详细解析:组合注解,包含Configuration(标记配置类)、EnableAutoConfiguration(开启自动配置)、ComponentScan(组件扫描)。启动类标注后,Spring …

基于原神游戏物品系统小demo制作思路

概述 本文介绍了一个基于C的游戏物品与角色管理系统,该系统实现了游戏中的物品分类、角色属性管理、队伍组建以及背包物品使用等功能。该系统采用面向对象的设计原则,通过继承和多态实现了可扩展的物品效果系统。 系统架构 1. 物品类型系统 系统定义了三…

Grounded-Segment-Anything 环境配置

Grounded-Segment-Anything 环境配置Grounded-Segment-Anything 介绍环境配置Install osx(非必须):Install RAM & Tag2Text:报错 module ‘pkgutil‘ has no attribute ‘ImpImporter‘. Did you mean: ‘zipimporter‘?运行输出分割文本提示检测远…

ZYNQ 定时器

一、ZYNQ定时器简介 每个Cortex-A9处理器都有自己的专用32位定时器和32位看门狗定时器。两个处理器共享一个全局64位定时器。这些计时器的时钟始终为CPU频率(CPU_3x2x)的1/2。在系统级,有一个24位看门狗定时器和两个16位三重定时器/计数器。系…

Java8 Comparator接口 和 List Steam 排序使用案例

在Java中,Comparator接口主要用于实现自定义排序逻辑,适用于未实现Comparable接口或需要覆盖默认比较规则的场景。以下是核心使用方法和注意事项:一、基础用法‌匿名内部类实现‌传统方式通过匿名内部类重写compare()方法,例如对整…

word2vec模型案例

代码实现:import torch.optim as optim from tqdm import tqdm, trange import numpy as np import torch from torch import nn import torch.nn.functional as FCONTEXT_SIZE 2raw_text """We are about to study the idea of a computational p…

< 自用文 OS 有关 > (续)发现正在被攻击 后的自救 Fail2ban + IPset + UFW 工作流程详解

继上编:< 自用文 主机 USC 记录:> 发现正在被攻击 后的自救-CSDN博客 环境: 改进: 以下是把代码,懒得写,扔给了 AI ,让它出的: Fail2ban IPset UFW 工作…

Linux —— 虚拟进程地址空间

🎁个人主页:工藤新一 🔍系列专栏:C面向对象(类和对象篇) 🌟心中的天空之城,终会照亮我前方的路 🎉欢迎大家点赞👍评论📝收藏⭐文章 文章目录虚…

简单聊一聊js

JavaScript 是一种高级的、解释型的编程语言。它是现代 Web 开发的三大核心基石之一,与 HTML 和 CSS 并列。​HTML​:负责网页的结构和内容​(如标题、段落、图片)。​CSS​:负责网页的样式和布局​(如颜色…

造粒机cad+设计说明书

摘要 随着现代化工业的快速发展,生产出大量的固体废弃物。这些废弃物对环境造成了很大的污染,因此需要采取有效的措施进行处理。机械强压式造粒机就是一种非常有效的处理工具,它可以将废渣、废料、饲料和化肥等材料通过机械强力挤压&#xff…