资讯详情

资讯详情

信息量、信息熵与信息增益:从概念到决策树实战与MATLAB计算

要说机器学习入门阶段最“劝退”的一批概念信息量、信息熵、信息增益绝对排得上号。我刚接触决策树那会儿公式能背下来可真拿到一批数据却搞不清什么时候该算信息量、什么时候该算熵算出来的信息增益大小又说明什么。直到把这三个概念放进同一条逻辑链里才彻底想明白它们其实是一条线下来的从“某一条消息有多意外”到“整个系统有多混乱”再到“某个特征能帮我消除多少混乱度”。这篇文章就把这条线完整捋一遍顺便讲讲 matlab 里怎么算一维数据信息熵以及在决策树里信息增益到底怎么用。1. 信息量概率越小消息越值钱1.1 “重要消息”和“废话消息”的差别信息量这个概念其实每个人都有直觉。你手机上同时弹出两条通知一条说“太阳今天从东边升起”另一条说“本期彩票开奖号码是XX”你会觉得第一条几乎没有信息量第二条信息量爆炸。同样的道理一句“明天太阳照常升起”没人会觉得新鲜但“明天凌晨小区要停水停电”肯定会让你立刻开始做应对准备。这个直觉和信息论里的定义完全一致信息量的大小不由消息本身的“字数”决定而由这条消息发生的概率决定。概率越大、越容易发生的事件确认它发生时你的认知几乎不被修正信息量就低概率越小、越意外的事件一旦确认你的认知会被大幅更新信息量就高。所以你会发现信息量本质上是用来衡量“意外程度”的。香农最早给这个直觉建立了数学模型于是有了严格定义下的自信息self-information。1.2 自信息的数学定义和单位设事件 (x) 发生的概率是 (P(x))它的信息量定义为[ I(x) -\log_2 P(x) ]为什么用负对数两个原因。第一概率 (P(x)) 一定在 0 到 1 之间直接取对数是负数加个负号让信息量永远为正。第二对数运算有一个非常好的性质两条独立事件同时发生的信息量等于各自信息量之和。因为概率相乘时 (\log(ab) \log a \log b)不管事件怎么组合信息量都可以直接相加这让计算变得非常方便。单位是 bit全称 binary digit。一个概率为 0.5 的事件信息量是 1 bit刚好对应“一个二进制位能表示的不确定性”。比如抛硬币正面概率 0.5那么“结果正面朝上”这条消息的信息量就是 1 bit。注意(P(x)) 就是我们熟知的概率。信息量公式看起来简单但它把所有“意外程度”量化成了可加减、可比较的数字这是后面所有熵相关计算的地基。1.3 用天气预报加深理解拿天气预报举一个具体例子。假设某地区晴天的概率是 0.6雨天的概率是 0.1。“今天下雨”这条消息的信息量[ I(雨) -\log_2 0.1 \approx 3.32 \text{ bit} ]“今天晴天”这条消息的信息量[ I(晴) -\log_2 0.6 \approx 0.74 \text{ bit} ]同样是“今天下雨”和“今天晴天”这几个字信息量差了差不多 4.5 倍。原因很简单这个地区极少下雨真下了雨说明天气出了明显的反常你获得的新信息多晴天是常态不构成任何“新闻”。这就是信息量最直观的样子概率越低越意外越值钱。2. 信息熵整个系统的平均不确定性2.1 从单条消息扩展到一组概率分布信息量回答的是“某一条具体消息值多少”但实际场景里我们往往要面对一个完整的系统这个系统有一组可能取值每个取值各有概率。这时候就需要一个指标来描述“拿到结果之前这个系统平均让我承担多少不确定性”。香农的回答是信息熵。定义如下[ H(X) -\sum_{i1}^{n} P(x_i) \log_2 P(x_i) ]也就是说把每一个可能取值的信息量按照它的概率做加权平均。这个结果就叫信息熵。它衡量的是整个系统的不确定程度也叫平均自信息。为什么叫“熵”香农当时借用了热力学里“熵”的概念。热力学熵描述一个系统的混乱程度信息熵描述一个概率系统的不确定程度本质上是很像的。不需要深究物理学背景记住一句话就够了熵越大系统越混乱越难预测。2.2 手算两个例子建立直觉先看最简单的抛硬币。正面概率 0.5反面概率 0.5[ H -0.5 \times \log_2 0.5 - 0.5 \times \log_2 0.5 0.5 0.5 1 \text{ bit} ]一个硬币两种结果各占一半熵为 1 bit非常符合直觉系统恰好需要一个二进制位来区分“正”和“反”。再看上面的天气例子。晴天概率 0.6阴天概率 0.3雨天概率 0.1[ H -(0.6 \times \log_2 0.6 0.3 \times \log_2 0.3 0.1 \times \log_2 0.1) \approx 1.30 \text{ bit} ]如果把概率换成完全均匀的三分类每种 (1/3)[ H -\sum_{i1}^{3} \frac{1}{3} \log_2 \frac{1}{3} \log_2 3 \approx 1.585 \text{ bit} ]很明显均匀分布时熵更大。原因也很直接当三种天气概率完全相等时你没有任何先验偏好预测难度最大而实际概率分布有偏向性晴天占了六成系统整体上没那么难以预测所以熵更小。2.3 信息熵的几个性质信息熵有三个性质值得专门说非负。每一项 (P(x_i)) 是正概率(-\log_2 P(x_i)) 也是非负的所以熵一定大于等于 0。当某个事件概率为 1、其余都为 0 时熵为 0。这时候系统完全确定没有任何不确定性。在取值个数固定时概率分布越均匀熵越大取值个数越多熵的上限也越高。最后一个性质经常被忽略但工程上很关键。两个特征的熵做比较之前先确认它们的取值个数在同一量级否则结果没有可比性后面我会专门讲这个坑。3. matlab中怎么计算一维数据信息熵3.1 离散数据先统计频次再套公式v如果手头是一组离散数据比如类别标签、性别、天气类型这些计算信息熵的思路是先统计每个取值出现的次数除以总样本数得到概率估计值再带入信息熵公式。这里给一段可以直接跑的 MATLAB 代码% 一维离散数据的信息熵计算 data [1 2 2 3 1 2 1 1 3 3 2 1]; labels unique(data); n numel(data); p zeros(size(labels)); for i 1:numel(labels) p(i) sum(data labels(i)) / n; end % 剔除概率为0的项避免log2(0)出现NaN p(p 0) []; H -sum(p .* log2(p)); fprintf(信息熵: %.4f bit\n, H);逐行说下思路。unique(data)取出所有可能取值sum(data labels(i))统计某个值出现的次数除以总数n得到频率用频率估计概率最后一句就是标准的熵公式。这里需要注意用频率代替概率本质上是极大似然估计。如果样本数量太少频次估计会偏差很大算出来的熵值不可靠。比如只有 3 个样本、每个取值都不同熵会被算成 (\log_2 3)但这个结果并不代表真实世界。3.2 连续数据先分桶再计算熵连续数值数据比如身高、温度、点击时长这类直接套公式没有概率可用因为每个值几乎都是唯一的。更常见的做法是先把连续变量离散化也就是分桶。% 一维连续数据的信息熵计算 rng(42); data randn(1, 2000); % Sturges公式确定分桶数k 1 log2(n) k round(1 log2(numel(data))); [counts, ~] histcounts(data, k); p counts / sum(counts); p(p 0) []; H -sum(p .* log2(p)); fprintf(一维连续数据信息熵: %.4f bit\n, H);分桶数选择有很多经验规则Sturges 公式是最常用的一个[ k 1 \log_2 n ]其中 (n) 是样本数。对于 2000 个样本算出来约 12 个桶。桶数多少对结果影响很大桶越多可能的取值就越多系统不确定性越高熵值也会越大。所以如果有多个特征做对比分桶策略必须统一否则熵根本没有可比性。提示MATLAB 里没有现成的、像某些 Python 库一样直接算信息熵的官方函数别浪费时间去搜索工具箱。几行代码自己写最稳定也最容易改造成符合业务逻辑的版本。3.3 三个经常踩到的坑第一个坑是log2(0)的问题。当某个概率正好为 0 时(0 \times \log_2 0) 在数学上约定为 0但 MATLAB 里直接算会产生 NaN后面所有结果都废掉。解决办法就是在计算前用p(p 0) []把零概率剔除。第二个坑是histcounts的分桶数必须是个正整数。如果用公式算出 11.97 之类的小数MATLAB 会直接报错记得round一下。第三个坑是字符型或元胞型数据不能直接使用histcounts因为分桶函数本质是数值区间统计。处理这类数据请回到unique 循环统计频率的方式。4. 决策树信息增益如何挑选最有效的特征4.1 条件熵知道特征后还剩多少不确定性信息量针对单条消息信息熵针对整个系统而信息增益回答的是一个更实际的问题如果我知道了某个特征的取值目标变量会变得多确定先看条件熵 (H(Y|X))它表示在已知特征 (X) 的条件下目标变量 (Y) 还剩下多少不确定性[ H(Y|X) \sum_{j} P(X x_j) \cdot H(Y | X x_j) ]做法是把样本按特征 (X) 的取值分成若干组每组单独计算目标变量 (Y) 的信息熵再按该组样本比例加权平均。这样可以理解成一堆混合样本被某个特征切分成若干个子堆每个子堆的内部混乱度加权求和就是切分之后的整体剩余不确定性。信息增益就是熵的下降量[ Gain(Y, X) H(Y) - H(Y|X) ]如果某个特征能让分组后每个子堆都变得很“纯”条件熵趋近 0信息增益就很大说明它对预测目标非常有价值。决策树要做的事情就是在根节点和每个内部节点上从所有候选特征中挑出信息增益最大的那个。4.2 用打网球数据集完整算一遍为了把流程讲透我用了经典的打网球数据集一共 14 条记录特征包括 Outlook、Temperature、Humidity、Wind目标变量是 Play取值 Yes 或 No。DayOutlookTemperatureHumidityWindPlayD1SunnyHotHighWeakNoD2SunnyHotHighStrongNoD3OvercastHotHighWeakYesD4RainyMildHighWeakYesD5RainyCoolNormalWeakYesD6RainyCoolNormalStrongNoD7OvercastCoolNormalStrongYesD8SunnyMildHighWeakNoD9SunnyCoolNormalWeakYesD10RainyMildNormalWeakYesD11SunnyMildNormalStrongYesD12OvercastMildHighStrongYesD13OvercastHotNormalWeakYesD14RainyMildHighStrongNo第一步计算总熵。14 条记录里 Yes 有 9 条No 有 5 条[ H(S) -\frac{9}{14} \log_2 \frac{9}{14} - \frac{5}{14} \log_2 \frac{5}{14} \approx 0.940 \text{ bit} ]第二步按 Outlook 划分。Sunny 有 5 条其中 Yes 2、No 3熵约 0.971Overcast 有 4 条全部 Yes熵为 0Rainy 有 5 条其中 Yes 3、No 2熵约 0.971。[ H(S|Outlook) \frac{5}{14} \times 0.971 \frac{4}{14} \times 0 \frac{5}{14} \times 0.971 \approx 0.694 ][ Gain(S, Outlook) 0.940 - 0.694 0.246 ]第三步同样方法计算另外三个特征。Humidity 分成 High 和 Normal 两组High 组 7 条约 0.985Normal 组 7 条约 0.592条件熵约 0.788增益 0.152。Wind 分成 Weak 和 Strong 两组条件熵约 0.892增益只有 0.048。Temperature 分成 Hot、Mild、Cool 三组条件熵约 0.911增益约为 0.029。把四个特征的信息增益放一起特征条件熵信息增益是否最优Outlook0.6940.246是Humidity0.7880.152否Wind0.8920.048否Temperature0.9110.029否结论很明显Outlook 的信息增益最大决策树根节点应该选 Outlook。这个结果也符合常规认知有没有太阳、是否阴天对决定是否去打网球的影响确实是最大的。4.3 信息增益的局限性信息增益好用但有一个明显缺陷它偏爱取值特别多的特征。假设把样本编号 Day 也作为一个特征它有 14 个取值每个取值正好一个样本每个分组内部的熵都是 0条件熵就是 0信息增益直接顶到总熵 0.940。但这个特征放到未来新数据上毫无泛化能力。这也是 ID3 算法后来的改进方向。C4.5 用信息增益率通过除以特征自身熵来惩罚取值过多的特征CART 用基尼指数思想类似但不直接依赖对数计算数学上更轻量。理解信息增益是理解这些变体的前提因为它们的出发点都是“如何让分组之后更纯”。工程建议如果你在用决策树或随机森林默认特征分裂指标大概率是基尼或者信息增益相关的变体。遇到模型输出里“某个不重要特征被排在前面”的情况先想想它是不是取值特别多再判断是不是信息增益偏向性在作怪。5. 概念容易混的三个地方与实操心得5.1 一句话区分三个核心概念很多人绕不明白这三个概念其实完全可以压缩成三句话信息量描述某一条具体消息的意外程度公式 (I-\log_2 P(x))。信息熵描述整个系统所有消息的平均不确定程度公式 (H-\sum P(x)\log_2 P(x))。信息增益描述知道特征 (X) 后目标 (Y) 的不确定性下降多少公式 (GainH(Y)-H(Y|X))。信息量是对“点”的描述信息熵是对“面”的描述信息增益是对“面”的差分变化。想清楚这个关系什么时候用哪个自然就清楚了。5.2 实际工程中怎么用这几个指标我在真实项目中用信息增益比较多的地方是特征预筛选。一批新数据进来先不急着建模把每个特征和目标变量算一遍信息增益能很快找出完全没区分度的特征。举个例子在某个用户行为分析项目里十几个候选特征算下来有三个信息增益几乎为 0直接在下游建模时排除模型训练速度明显提升精度没有下降。不过这里有几个必须注意的点。第一连续特征必须先做离散化而且统一用相同的分桶策略否则不同特征的增益值没有可比性。第二取值很多的特征增益天然偏大跟真实预测能力不完全挂钩判断时要结合业务逻辑或交叉验证。第三样本量太少时频率估计不可靠信息增益也会虚高或虚低建议至少有几百条数据再参考这个指标。5.3 一个自检代码的小技巧如果你自己写了信息熵计算代码有几句宝贵经验先用极端情况验证。把数据改成所有取值都相同熵应当等于 0把数据改成每个取值出现次数完全均匀熵应当等于 (\log_2(\text{类别数}))。这两个测试通过基本可以确定公式实现没有写错。我封装一个简单函数作为参考function H calc_entropy(data) labels unique(data); n numel(data); p zeros(size(labels)); for i 1:numel(labels) p(i) sum(data labels(i)) / n; end p(p 0) []; H -sum(p .* log2(p)); end这个函数处理离散数据和已经离散化的连续数据都够用。实测下来就算数据量到百万级别循环统计频次依然是毫秒级性能不用太担心。真要说瓶颈反而是在数据读取和预处理环节。我个人现在的习惯是拿到一批新数据后先看一眼目标变量的信息熵。如果熵非常小说明类别几乎只集中在一种直接做常规分类意义不大更该考虑是否要做异常检测或者重新设计标签。这个习惯帮我避免了不少白费功夫的建模尝试。搞懂信息熵之后你会发现很多机器学习算法背后的逻辑都不再玄乎——所谓特征选择、分裂规则、模型提升本质上都是在想办法降低我们需要承担的不确定性。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →