Python-深度学习--2信息熵,条件熵(ID3决策树),KL散度

一、信息熵(Entropy)的计算与应用

信息熵用于衡量一个概率分布的不确定性,值越大表示分布越分散(不确定性越高)。

1. 数学定义

对于离散概率分布 P,信息熵公式为:

(通常以 2 为底单位是比特,以 e 为底单位是纳特,实际使用中可统一底数)

import numpy as np
from scipy.stats import entropy  # scipy内置熵计算函数def manual_entropy(p):"""手动计算信息熵(确保p是归一化的概率分布)"""# 过滤0概率(避免log(0)无意义)p = p[p > 0]return -np.sum(p * np.log(p))  # 以e为底,若需以2为底可改用np.log2# 示例1:均匀分布(不确定性最高)
p_uniform = np.array([0.25, 0.25, 0.25, 0.25])  # 4个事件等概率
print("均匀分布手动计算熵:", manual_entropy(p_uniform))  # 输出:1.386...(ln4)
print("均匀分布scipy计算熵:", entropy(p_uniform))  # 与手动计算一致# 示例2:极端分布(确定性最高)
p_deterministic = np.array([1.0, 0.0, 0.0, 0.0])  # 只有第一个事件有概率
print("极端分布熵:", entropy(p_deterministic))  # 输出:0.0(无不确定性)# 示例3:实际应用(文本字符分布的熵)
text = "hello world"
char_counts = np.array([text.count(c) for c in set(text)])
char_probs = char_counts / len(text)  # 字符概率分布
print("文本字符分布的熵:", entropy(char_probs))  # 衡量文本字符多样性

运行结果 :

均匀分布手动计算熵: 1.3862943611198906
均匀分布scipy计算熵: 1.3862943611198906
极端分布熵: 0.0
文本字符分布的熵: 1.5607104090414068
2. Python 实现(手动计算 + 库函数)
import numpy as np
from scipy.stats import entropy  # scipy内置熵计算函数def manual_entropy(p):"""手动计算信息熵(确保p是归一化的概率分布)"""# 过滤0概率(避免log(0)无意义)p = p[p > 0]return -np.sum(p * np.log(p))  # 以e为底,若需以2为底可改用np.log2# 示例1:均匀分布(不确定性最高)
p_uniform = np.array([0.25, 0.25, 0.25, 0.25])  # 4个事件等概率
print("均匀分布手动计算熵:", manual_entropy(p_uniform))  # 输出:1.386...(ln4)
print("均匀分布scipy计算熵:", entropy(p_uniform))  # 与手动计算一致# 示例2:极端分布(确定性最高)
p_deterministic = np.array([1.0, 0.0, 0.0, 0.0])  # 只有第一个事件有概率
print("极端分布熵:", entropy(p_deterministic))  # 输出:0.0(无不确定性)# 示例3:实际应用(文本字符分布的熵)
text = "hello world"
char_counts = np.array([text.count(c) for c in set(text)])
char_probs = char_counts / len(text)  # 字符概率分布
print("文本字符分布的熵:", entropy(char_probs))  # 衡量文本字符多样性
3. 应用场景
  • 特征选择:计算特征值的熵,熵越高表示特征越分散,可能包含更多信息。
  • 决策树:ID3/C4.5 算法用信息熵计算 “信息增益”,选择最优分裂特征。
  • 文本分析:通过字符 / 词频分布的熵衡量文本复杂度(熵越高,字符分布越均匀)。

补充:

步骤 1:计算数据集的总信息熵 H(D)

以经典的 “天气与是否打球” 数据集为例(共 14 条样本):

编号天气(A)温度(B)湿度(C)风速(D)是否打球(标签)
1hot
2hot
3hot
..................
14cool

标签 “是否打球” 中,“是” 有 9 条,“否” 有 5 条,总熵:H(D)=−149​log2​(149​)−145​log2​(145​)≈0.940

步骤 2:对每个特征计算信息增益

以特征 “天气(A)” 为例,其取值为 “晴、阴、雨”:

  • 晴(5 条):2 条 “是”,3 条 “否” → 晴
  • 阴(4 条):4 条 “是”,0 条 “否” → 阴(确定无不确定性)
  • 雨(5 条):3 条 “是”,2 条 “否” → 雨

条件熵:H(D∣A)=145​×0.971+144​×0+145​×0.971≈0.693

信息增益:Gain(D,A)=H(D)−H(D∣A)=0.940−0.693=0.247

同理计算其他特征(温度、湿度、风速)的信息增益,假设结果为:

  • 湿度(C)的信息增益最大(约 0.151),则 ID3 选择 “湿度” 作为根节点的分裂特征。
步骤 3:递归构建决策树

对每个特征取值的子集(如 “湿度 = 高”“湿度 = 正常”),重复步骤 1-2,计算子数据集的信息增益,选择下一个分裂特征,直到所有样本属于同一类别或无特征可分。

三、C4.5 算法步骤(改进 ID3 的信息增益比)

C4.5 的核心是用信息增益比替代信息增益,避免 ID3 偏向取值多的特征(如 “日期” 这类取值多的特征可能信息增益高,但无实际意义)。

步骤 1:计算信息增益(同 ID3)

沿用 ID3 中 “天气(A)” 的计算,Gain(D,A)=0.247。

步骤 2:计算特征的熵 HA​(D)

特征 “天气” 有 3 个取值,样本占比分别为 5/14,4/14,5/14:HA​(D)=−145​log2​145​−144​log2​144​−145​log2​145​≈1.577

步骤 3:计算信息增益比

Gain_ratio(D,A)=1.5770.247​≈0.156

对所有特征计算信息增益比,选择增益比最大的特征作为分裂节点(C4.5 通常先筛选信息增益高于平均的特征,再从中选增益比最大的,避免增益接近 0 的特征)。

四、Python 代码实现(ID3 算法示例)

以下用 Python 手动实现 ID3 算法,核心包括信息熵计算、信息增益计算和决策树构建:

import numpy as np
from math import log2   #导入对数函数,用于计算信息熵
import pprint           #导入格式化打印工具,使决策树更易读# 1. 计算信息熵(输入:标签列表,如 ['是', '否', '是', ...])
def entropy(labels):"""计算标签列表的信息熵"""# 统计每个类别的数量   字典储存 :键 = 标签, 值 = 出现次数label_counts = {}for label in labels:        #遍历所有标签#如果标签在字典中,次数+1,否则初始化为1label_counts[label] = label_counts.get(label, 0) + 1ent = 0.0                   #初始化信息熵为0total = len(labels)         #总样本数for count in label_counts.values():  #遍历每个类别的数量p = count / total                #计算该类别的概率ent -= p * log2(p)  # 信息熵公式return ent              # 返回计算好的信息熵#作用:衡量数据集的不确定性,值越大表示越混乱
#关键逻辑:用字典统计标签出现次数,带入熵公式计算# 2. 计算信息增益(输入:特征值列表、标签列表)
def information_gain(feature_values, labels):"""计算某一特征的信息增益"""total_ent = entropy(labels)  # 计算总熵total_samples = len(labels)  # 总样本数# 按特征值分组,统计每个取值对应的标签feature_groups = {}  # key: 特征值, value: 该取值对应的标签列表for f_val, label in zip(feature_values, labels):#同时遍历特征值和标签if f_val not in feature_groups:             #如果特征值未记录,初始化列表feature_groups[f_val] = []feature_groups[f_val].append(label)# 计算条件熵 H(D|A):已知特征A的取值后,数据集的不确定性cond_ent = 0.0for group_labels in feature_groups.values():   # 遍历每个特征值对应的标签列表group_size = len(group_labels)             # 该特征值的样本数# 条件熵 = 求和(该组样本占比 * 该组信息熵)cond_ent += (group_size / total_samples) * entropy(group_labels)return total_ent - cond_ent  # 信息增益 = 总熵 - 条件熵# 3. 选择信息增益最大的特征(输入:特征列表、标签列表)
def choose_best_feature(features, labels):"""选择最佳分裂特征features: 特征列表,格式为 [[f1_val, f1_val, ...], [f2_val, ...], ...]每个子列表对应一个特征的所有取值labels: 标签列表"""best_gain = -1best_feature_idx = 0  # 最佳特征的索引# 遍历每个特征计算信息增益for i in range(len(features)):feature_values = features[i]gain = information_gain(feature_values, labels)if gain > best_gain:  #如果当前增益更大,更新最佳增益和索引。best_gain = gainbest_feature_idx = ireturn best_feature_idx, best_gain  #返回最佳的索引和对应的增益# 4. 递归构建ID3决策树
def build_tree(features, labels, feature_names, depth=0, max_depth=5):"""构建决策树features: 特征列表(格式同上)labels: 标签列表feature_names: 特征名称列表(用于树结构的可读性)"""# 终止条件1:所有标签相同,返回该类别if len(set(labels)) == 1:return labels[0]# 终止条件2:无特征可分或达到最大深度,返回多数类if len(features) == 0 or depth >= max_depth:# 统计多数类label_counts = {}for label in labels:label_counts[label] = label_counts.get(label, 0) + 1return max(label_counts, key=label_counts.get)  # 多数类标签# 选择最佳特征best_idx, _ = choose_best_feature(features, labels)best_feature_name = feature_names[best_idx]best_feature_values = features[best_idx]  # 最佳特征的所有取值# 初始化树结构:以最佳特征为根节点tree = {best_feature_name: {}}# 移除已选择的特征(剩余特征用于子树)remaining_features = [features[i] for i in range(len(features)) if i != best_idx]remaining_feature_names = [feature_names[i] for i in range(len(feature_names)) if i != best_idx]# 按最佳特征的取值分组,递归构建子树unique_values = set(best_feature_values)  # 最佳特征的所有 unique 取值for val in unique_values:# 筛选出该特征值对应的样本索引sample_indices = [i for i, f_val in enumerate(best_feature_values) if f_val == val]# 提取子样本的特征和标签sub_labels = [labels[i] for i in sample_indices]sub_features = []for f in remaining_features:  #遍历剩余特征#提取该特征在子样本中的取值sub_f = [f[i] for i in sample_indices]sub_features.append(sub_f)# 递归构建子树,深度+1 ,并将结果存入当前树结构tree[best_feature_name][val] = build_tree(sub_features, sub_labels, remaining_feature_names, depth + 1, max_depth)return tree# 5. 测试:用天气数据集构建决策树
if __name__ == "__main__":# 构造天气数据集(不依赖pandas,用列表存储)# 特征名称列表feature_names = ['天气', '温度', '湿度', '风速']# 特征值列表:每个子列表对应一个特征的所有取值features = [['晴', '晴', '阴', '雨', '雨', '雨', '阴', '晴', '晴', '雨', '晴', '阴', '阴', '雨'],  # 天气['hot', 'hot', 'hot', 'mild', 'cool', 'cool', 'cool', 'mild', 'cool', 'mild', 'mild', 'mild', 'hot', 'mild'],# 温度['高', '高', '高', '高', '正常', '正常', '正常', '高', '正常', '正常', '正常', '高', '正常', '高'],  # 湿度['弱', '强', '弱', '弱', '弱', '强', '强', '弱', '弱', '弱', '强', '强', '弱', '强']  # 风速]# 标签列表 (是否打球)labels = ['否', '否', '是', '是', '是', '否', '是', '否', '是', '是', '是', '是', '是', '否']  # 是否打球# 构建ID3决策树 (最大深度为3)id3_tree = build_tree(features, labels, feature_names, max_depth=3)# 打印决策树结构 (用pprint格式化输出,更易读)print("ID3决策树结构:")pprint.pprint(id3_tree)

二、KL 散度(Kullback-Leibler Divergence)的计算与应用

KL 散度用于衡量两个概率分布的差异,值越小表示分布越接近(非对称度量)。

1. 数学定义

对于两个离散概率分布 P(真实分布)和 Q(近似分布),KL 散度公式为:

import numpy as np
from scipy.stats import kl_div  # scipy内置KL散度计算def manual_kl_divergence(p, q):"""手动计算KL散度(确保p和q是同维度的归一化概率分布)"""# 过滤0概率(避免log(0)和除以0)p = p[p > 0]q = q[p > 0]  # 只保留p有概率的位置q = np.clip(q, 1e-10, 1.0)  # 防止q为0导致除零错误return np.sum(p * np.log(p / q))# 示例1:两个相似分布的KL散度
p = np.array([0.4, 0.3, 0.3])
q_similar = np.array([0.35, 0.35, 0.3])
print("相似分布手动KL散度:", manual_kl_divergence(p, q_similar))  # 输出:0.014...
print("相似分布scipy KL散度:", np.sum(kl_div(p, q_similar)))  # 与手动计算一致(scipy返回每个元素的KL值,需求和)# 示例2:两个差异大的分布的KL散度
q_different = np.array([0.1, 0.1, 0.8])
print("差异分布KL散度:", np.sum(kl_div(p, q_different)))  # 输出:0.396...(值更大)# 示例3:KL散度的非对称性(P到Q与Q到P的散度不同)
print("D(P||Q):", np.sum(kl_div(p, q_similar)))
print("D(Q||P):", np.sum(kl_div(q_similar, p)))  # 结果不同,体现非对称性
3. 应用场景
  • 模型评估:衡量预测分布与真实分布的差异(如生成模型中,评估生成数据分布与真实数据分布的差距)。
  • 分布对齐:在迁移学习中,用 KL 散度最小化源域与目标域的分布差异。
  • 变分自编码器(VAE):用 KL 散度约束潜在变量分布接近标准正态分布。
  • 正则化:在半监督学习中,用 KL 散度限制模型对未标记数据的预测分布熵(如一致性正则化)。

 

 

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

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

相关文章

国产化Word处理控件Spire.Doc教程:Python提取Word文档中的文本、图片、表格等

在现代办公场景中,Word文档已成为信息存储与交流的重要载体,承载着关键的业务数据、结构化表格、可视化图表以及协作批注等重要内容。面对日益增长的文档处理需求,传统的人工操作方式已难以满足效率与准确性的双重标准。采用Python实现Word文…

Spring IOC 原理

Spring IoC(控制反转)是Spring框架的核心机制,其原理是通过容器管理对象生命周期和依赖关系,实现解耦。 1. 控制反转(IoC)核心思想 传统模式:对象主动创建依赖(如new Service()&…

VSCode:基础使用 / 使用积累

官网 Visual Studio Code - Code Editing. Redefined 记录一、更新依赖 尝试删除yarn.lock文件 记录二、“解决冲突”的方式变了 更新后,“解决冲突”的方式变了,有的时候能选中两者,有的时候不能 现在又更新了,回复到了原来…

tcp 确认应答和超时时间

1. 确认应答之间的时间(RTT)这是指 从发送方发送数据到接收方返回确认(ACK)之间的时间。它反映的是数据传输的 往返延迟。例如,发送方发送一个数据包,接收方收到后,回传一个确认包(A…

图的应用-最短路径

最短路径的典型用途:交通网络的问题——从甲地到乙地之间是否有公路连通?在有多条通路的情况下,哪一条路最短?交通网络用有向网来表示:顶点——表示地点,弧——表示两个地点有路连通,弧上的权值…

【qt5_study】1.Hello world

模板 作为初学者我们选择第一个Application(Qt)和 Qt Widgets Application,所谓的模板就是 Qt为了方便开发程序,在新建工程时可以让用户基于一种模板来编写程序,包括 cpp文件, ui文件都已经快速的创建,而不用用户手动创建这些文件。 基类 这里默认选择的基类为 QMainWin…

项目构想|文生图小程序

Date: August 4, 2025项目介绍 👋,我们通过 Vibe Coding 做一个文字生成图片的小程序。 我们会从需求分析、技术选型、UI设计、项目构筑到最后打包,一路尝试 Vibe Coding 实现。 创建项目 创建文件夹:ai-pic-mini-app 采用 Git 进…

TiDB/MongoDB/Taosdb存储引擎概览

数据库类型存储引擎数据结构源码位置tidbRockDBLSM树https://github.com/facebook/rocksdbmongodbWiredTigerB 树/LSM树https://github.com/wiredtiger/wiredtigerTDengineTSDBBRINhttps://github.com/taosdata/TDengine 1、tidb存储引擎概览 LSM树数据结构描述LSM树(Log Str…

qt窗口--01

文章目录qt窗口--01窗口概览菜单栏工具栏状态栏浮动窗口子窗口对话框model结语很高兴和大家见面,给生活加点impetus!!开启今天的编程之路!! 作者:٩( ‘ω’ )و260 我的专栏:qt,Li…

Neo4j 社区版 Mac 安装教程

最近用到了nebulagraph图数据库做金融反欺诈项目,虽然nebula属于分布式架构,但依然感觉nebula使用不太顺手,这里顺便研究一下neo4j这款数据库如何,这里先从安装开始? 一、 准备工作 确认 Java 版本要求: N…

Android Studio(2025.1.2)Gemini Agent 使用指南

Android Studio(2025.1.2)Gemini Agent 使用指南 文章目录Android Studio(2025.1.2)Gemini Agent 使用指南1. 什么是 Gemini Agent?2. 如何启用和配置 Gemini Agent2.1 获取 API Key2.2 在 Android Studio 中配置3. 实…

计算机视觉--opencv(代码详细教程)

在计算机视觉的广袤领域中,OpenCV 是一座极为关键的里程碑。无论是在前沿的学术研究,还是在蓬勃发展的工业界,OpenCV 凭借其强大的功能与高效的性能,为开发者提供了丰富的图像处理和计算机视觉算法,助力无数项目落地。…

Centos6停止服务后yum改用阿里云

环境: OS:Centos 6.9 1.进入到yum配置目录 cd /etc/yum.repos.d 2.备份 cp CentOS-Base.repo CentOS-Base.repo.bk 3.下载 wget -O CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-6.repo 问题1: 因为Centos-6早就停止了更新维护,阿里云镜像网站将其仓库…

putty+Xming(XLaunch) 远程登录VirtualBox中的Ubuntu24.04,显示图形化(GUI)界面

测试环境:VirtualBox 7,Ubuntu24.04 desktop,Ubuntu24.04 Server(no desktop),均测试成功。 一、先测试putty远程登录VirtualBox中的Ubuntu,可以使用ssh、Telnet 等协议。参见拙文《ssh连接VirtualBox中的Ubuntu24.04(win11、put…

SpringBoot微头条实战项目

一、项目概述 微头条是一个基于现代技术栈构建的新闻发布和浏览平台,旨在为用户提供便捷的新闻阅读体验和高效的新闻管理功能。该项目通过前后端分离的架构设计,实现了用户注册、登录、新闻浏览、搜索、发布、修改和删除等功能,同时通过JWT技…

如何给电脑换个ip地址?电脑换ip几种方法

更换电脑的IP地址的方法取决于你的具体需求和网络环境(是换本地局域网IP还是换对外公网IP)。以下是几种常见的方法: 一、更换本地局域网IP地址(在同一个网络内) 这个IP地址通常由你的路由器(或公司的网络管…

Pytest项目_day04(Python做接口请求)

Requests包 在python中,可以使用requests包,用于做接口请求和接口测试request支持http和https简单的get函数调用如下:r.jsonr.status_coder.textget函数的带params用法post函数的带params用法 post也可以和get一样在url中传入参数在requests包…

Flink与Kafka核心源码详解-目录

Flink是Apache软件基金会下开源的分布式流批一体计算框架,具备实时流计算和高吞吐批处理计算的大数据计算能力。本专栏内容为Flink源码解析的记录与分享。 本文解析的Flink源码版本为:flink-1.19.0 以下为Flink-1.19.0-完整源码详解的目录导航。 Flink-…

【VLLM篇】:原理-实现

1、VLLM vLLM是一个建立在【PagedAttention】之上的高吞吐的【分布式服务引擎】,目标是【提高吞吐量】、【提高内存利用率】(kv-cache内存利用率高达96%),它的内存管理分配方式从【固定分配】改进为【分页管理】,类似操…

什么是 TcpCommunicationSpi

&#x1f9e9; 一、核心定位&#xff1a;什么是 TcpCommunicationSpi&#xff1f; /*** <tt>TcpCommunicationSpi</tt> is default communication SPI which uses* TCP/IP protocol and Java NIO to communicate with other nodes.*/翻译&#xff1a;TcpCommunicat…