信息熵与信息增益:从信息量到决策树特征选择的完整指南

发布时间:2026/9/18 15:45:54
信息熵与信息增益:从信息量到决策树特征选择的完整指南 1. 信息量与“越意外越有料”的反直觉规律聊信息论之前先把一个最容易被忽略的概念拎出来信息量。很多人第一次接触这三个字都觉得“信息量”不就是“数据量”“内容多少”嘛。其实信息论里的信息量跟“多少”没关系它衡量的是“惊讶程度”——一件事发生得越意外携带的信息量越大。拿最常见的例子假如你住的城市明天太阳照常升起这事几乎百分之百确定有人专门跑来告诉你“明天太阳还会升起”你会觉得这是一句废话。信息量接近0。但如果有人告诉你“明天凌晨有月全食”这个事件的概率比较低你就觉得“有点东西”信息量就上来了。再极端一点如果有人说“明天市区地震”平时概率极低这条消息就炸了信息量极大。信息论对信息量的定义正是这样一个事件x的信息量 I(x) -log₂ P(x)P(x)是事件发生的概率。取负数的原因是概率在0到1之间对数算出来是负的取负号才能变成正值底数取2单位就是bit比特也便于和计算机里的二进制对齐。从这个公式能推导出一个很实用的规律概率每降低一半信息量增加1 bit。比如某事件概率是1/2信息量就是1 bit概率是1/4信息量就是2 bit概率是1/8信息量就是3 bit。想象一枚正常硬币抛出来正面朝上概率1/2给你带来的信息量就是1 bit但如果是一枚做了手脚的硬币正面概率99%偶然出了一次反面这一次反转带来的信息量大约是 log₂(1/0.01) ≈ 6.64 bit相当惊人。这正是信息论和直觉不一样的地方我们日常觉得“信息量大”的文章、视频往往是篇幅长、细节多但信息论里的信息量纯粹由“不确定性消除”的程度决定。一篇全是套话、车轱辘话来回说的长文信息量几乎为0而一句“这条路上有抓拍”的点拨信息量可能顶得上一整篇驾驶教程。建立这个认知很重要因为后面说信息熵和信息增益都是站在这条公式的地基上的。提示在机器学习里决策树分裂特征时用的“信息增益”本质逻辑就是“这条特征帮我消除了多少不确定性”。所以先别急着套公式把“信息量意外程度”这个直觉刻进脑子里后面全通了。2. 信息熵一个系统到底有多“乱”理解了单个事件的信息量信息熵就是它的“全家桶”版本。一个系统里可能有好几种结果每种结果有各自的概率。信息熵H(X)的定义是把所有可能结果的“信息量”按概率加权求平均。公式长这样H(X) -Σ P(x) log₂ P(x)说白了信息熵就是“这个系统平均每条消息带来的信息量”或者说“在知道结果之前系统整体有多不确定”。越不确定熵越大越确定熵越小。我常用一个比喻信息熵像一个房间的混乱程度。房间里的东西摆放得越随机、越无法预测你去收拾的时候要获取的信息就越多熵就高如果所有东西都在固定位置你一进门就知道哪拿哪放熵就低。极端情况有两种一是所有东西都整整齐齐也就是某个事件概率是1其余全是0这时候熵等于0完全没有不确定性二是所有位置都乱七八糟且概率均等比如抽屉里10件东西每件出现的概率都是1/10这时候熵达到最大值 log₂10 ≈ 3.32 bit。把公式拆开看有几个立即能用的结论概率越均匀熵越大。一个天气系统如果晴雨各半熵是1 bit如果晴天概率90%熵就只有约0.47 bit。均匀分布是最“没有倾向性”的状态也是最难预测的状态。状态越多熵越大。一个只有两种状态的系统最高熵是1 bit一个有8种等可能状态的系统最高熵是3 bit。因为你要用更多二进制位才能区分这么多状态。熵是非负的。概率都在0到1之间负对数非负加权平均后依然非负最小值是0。在机器学习里信息熵最常见的用途是当“杂质度”用。决策树划分数据集之前会先算一下当前数据集的熵。举个例子一个训练集里有100个样本其中50个是“买”50个是“不买”类别分布最均匀此时熵是1 bit说明数据非常“纠结”非常不纯如果样本里99个“买”、1个“不买”熵大约是0.08 bit数据几乎一边倒很纯。决策树算法的核心目标就是找到一个特征把数据从“纠结”切分成“不纠结”的子集。这里有个初学者特别容易混淆的点信息熵描述的是随机变量的不确定性不是某个具体样本的属性。不能说“这个样本的熵是多少”只能说“这堆样本的类分布熵是多少”。你按某个特征把所有样本分成两组每组各自算一个熵再按样本量加权平均这样才能得到“划分之后的总体纯度”。这个加权平均的过程正好是下一步信息增益的铺垫。3. 信息增益决策树“找茬”的核心指标假设你手里有一堆样本每个样本有若干特征每个特征都有一些取值你要做的就是让数据从“最混乱”变成“最有条理”。什么叫有条例就是按类别分得越开越好同一堆里最好全是一个类别。决策树做这件事的方式很“笨”也很有用挨个拿特征出来试算算“如果按这个特征划分混乱程度能降多少”。这个降低的量就是信息增益。公式长这样Gain(D, A) H(D) - H(D|A)其中H(D)是划分前数据集D的熵H(D|A)是已知特征A的取值后D的条件熵也就是按A的所有取值划分成多个子集后各子集熵的加权平均。用大白话说信息增益原来的不确定度-知道这个特征之后还剩下的不确定度。差值越大说明这个特征越能“一句话问到点子上”对消除混乱贡献越大。为什么这么设计我换个场景你就明白了。假设你要判断一个陌生人是不是篮球运动员面前摆着两个特征“身高”和“是否戴眼镜”。如果按“是否戴眼镜”划分你会发现两个子集里运动员比例差不多熵几乎没降增益接近0如果按“身高”分成高和矮高的那组里运动员比例明显偏高熵大幅下降增益就大。决策树在每一步都会挑增益最大的特征来分裂这本质上是在做“最有效的提问”——每次都用最能缩小答案范围的问题来缩小答案范围。这里有一个决策树实现里的关键点算条件熵H(D|A)时不是简单把所有子集熵加起来而是“按子集大小加权”。为什么因为决策树照顾的是整体纯度如果某个特征把数据切成一堆小碎块每块都特别纯但每块就一两个样本这样的划分对后续分类没意义。加权平均能压制这种“过度切碎”的倾向让大子集的贡献更突出。信息增益还有一个非常直观的几何解释它衡量的是“划分前后类别分布的变化幅度”。划分前是一个分布划分后是多个分布的加权混合信息增益就是这两个状态之间的“距离”。分类任务里这个距离越大说明特征和标签之间的关联越强。所以很多人用信息增益做特征选择原理也在这里先给每个特征算一遍信息增益排个序选增益大的特征子集能有效降低维度减少过拟合。注意信息增益有一个隐藏缺点——它天然偏向取值多的特征。比如“用户ID”这种特征每个样本一个值按它划分后每个子集只有一个样本子集熵全为0信息增益会直接拉满。但这样的特征完全没有泛化能力。这也是为什么后来的算法比如C4.5要用增益率来修正这个偏好。后面我会专门展开讲这个坑。4. 完整手算用“要不要发录用通知”把三概念串起来公式背得再多不如完整推一遍。我给你设计一个非常贴近工作的案例一个团队要根据候选人的3个特征决定“要不要发录用通知”。原始数据集有14个候选人特征分别是“学历”本科/硕士/博士、“工作经验”少于3年/3到5年/超过5年、“笔试成绩”高/中/低标签是“录用”是/否。样本分布如下编号学历工作经验笔试成绩录用1本科少于3年中否2本科少于3年高否3硕士少于3年低是4博士3到5年中是5本科超过5年高是6硕士3到5年低是7博士少于3年低否8硕士超过5年中是9本科少于3年高否10博士3到5年中是11硕士3到5年低是12博士超过5年低是13硕士超过5年高是14本科3到5年中否第一步算划分前的信息熵。14个人里录用6人不录用8人数一下是的有3、4、5、6、8、10、11、12、139个不对我重新数否1、2、7、9、145个是3、4、5、6、8、10、11、12、139个。等一下14个样本里明明是9个是和5个否。H(D) - (9/14) log₂(9/14) - (5/14) log₂(5/14) ≈ 0.940 bit。第二步按“学历”划分。学历有3个取值本科样本1、2、5、9、14其中录用1个5不录用4个熵H(本科) - (1/5) log₂(1/5) - (4/5) log₂(4/5) ≈ 0.722 bit。硕士样本3、6、8、11、13录用5个不录用0个熵H(硕士) 0。博士样本4、7、10、12录用3个4、10、12不录用1个7熵H(博士) - (3/4) log₂(3/4) - (1/4) log₂(1/4) ≈ 0.811 bit。条件熵H(D|学历) (5/14)×0.722 (5/14)×0 (4/14)×0.811 ≈ 0.258 0 0.232 ≈ 0.490 bit。信息增益Gain(D, 学历) 0.940 - 0.490 0.450 bit。第三步按“工作经验”划分。工作经验有3个取值少于3年样本1、2、3、7、9录用2个3、7不对7是不录用我重新数1否、2否、3是、7否、9否录用1个熵H(短) - (1/5) log₂(1/5) - (4/5) log₂(4/5) ≈ 0.722 bit。等一下样本3的录用是“是”所以短工作经验里录用1个、不录用4个。3到5年样本4、6、10、11、14录用4个4、6、10、11不录用1个14熵H(中) - (4/5) log₂(4/5) - (1/5) log₂(1/5) ≈ 0.722 bit。超过5年样本5、8、12、13录用4个不录用0个熵H(长) 0。条件熵H(D|工作经验) (5/14)×0.722 (5/14)×0.722 (4/14)×0 0.516 bit。信息增益Gain(D, 工作经验) 0.940 - 0.516 0.424 bit。第四步按“笔试成绩”划分。笔试成绩有3个取值低样本3、6、7、11、12录用4个3、6、11、12不录用1个7熵H(低) - (4/5) log₂(4/5) - (1/5) log₂(1/5) ≈ 0.722 bit。中样本1、4、8、10、14录用3个4、8、10不录用2个1、14熵H(中) - (3/5) log₂(3/5) - (2/5) log₂(2/5) ≈ 0.971 bit。高样本2、5、9、13录用2个5、13不录用2个2、9熵H(高) 1 bit。条件熵H(D|笔试成绩) (5/14)×0.722 (5/14)×0.971 (4/14)×1 ≈ 0.258 0.347 0.286 ≈ 0.891 bit。信息增益Gain(D, 笔试成绩) 0.940 - 0.891 0.049 bit。三个特征增益排个序学历0.450 工作经验0.424 笔试成绩0.049。所以决策树第一步会优先用“学历”做根节点的划分。这个结果也符合直觉在这个小样本里硕士学历的员工全员录用说明学历和工作录用的相关性最强笔试成绩几乎不提供额外区分度增益很低。注意我这里的样本是我自己构造的为了讲清楚算法故意让“硕士全录用”特别极端。真实数据集里极少有这么整齐的分布但计算逻辑完全一样。你完全可以拿这个表去Excel或者纸上自己验算一遍我建议你亲手算一次真的比看十遍公式都管用。5. 代码实操Python和MATLAB怎么算信息熵很多读到这里的人会问一个问题我知道公式了但实际处理一两千行数据总不能拿笔算吧确实工程场景里我们都是用代码来算。搜“matlab中怎么计算一维数据信息熵”的人不少说明大家对这块有实际需求。先说Python。计算信息熵最顺手的做法是结合numpy。核心就四步统计每个类别的数量、转成概率、代入熵公式、求和。给你一段可以直接跑的代码import numpy as np def entropy(labels): # 输入一维数组比如[yes,no,yes,...] # 输出该集合的信息熵单位bit _, counts np.unique(labels, return_countsTrue) probs counts / counts.sum() return -np.sum(probs * np.log2(probs)) # 试一下14个人里9个录用、5个不录用 labels [yes] * 9 [no] * 5 print(entropy(labels)) # 约0.940如果你在算决策树的信息增益可以用pandas按特征分组聚合import pandas as pd def conditional_entropy(data, feature, label): # data: DataFramefeature: 特征列名label: 标签列名 total len(data) result 0.0 for _, subset in data.groupby(feature): w len(subset) / total result w * entropy(subset[label].values) return result def info_gain(data, feature, label): base entropy(data[label].values) cond conditional_entropy(data, feature, label) return base - cond这段代码是教科书公式的直接翻译逻辑很清晰。实际做项目时如果特征列特别多几十上百个特征用循环逐个算也能扛住但如果数据量上百万行建议直接用sklearn里的mutual_info_classif或DecisionTreeClassifier底层用C实现速度不在一个量级。再说MATLAB。MATLAB里没有内置一个叫entropy的函数——这点很坑因为很多刚入门的人上来就搜“matlab熵函数”结果发现根本没有。其实一行就能写出来function H shannon_entropy(labels) % labels可以是数值向量或字符串元胞数组 tab tabulate(labels); probs tab(:, 3) / 100; % tabulate的第三列是百分比 probs probs(probs 0); H -sum(probs .* log2(probs)); end如果你手头数据已经是频数还可以更简单。比如你统计出某特征三个取值分别对应5、5、4个样本那熵就是counts [5, 5, 4]; probs counts / sum(counts); H -sum(probs .* log2(probs)); % 0.xxx用MATLAB算一维数据信息熵最容易踩的坑是tabulate在遇到单类别数据时百分比是100熵算出来是0这个没问题但如果你直接用histcounts它默认的bins可能把一个离散类别切成多段导致熵偏大。处理离散类别记住一个原则先unique去重再数频数别直接丢给直方图函数。我在实际写代码时有一个习惯算完熵先做个“空值测试”和“纯值测试”。空值测试就是传一个所有类别都不同的数组进去熵应该等于log₂(n)纯值测试就是传一个全是同一类别的数组熵应该是0。这两个边界值对了公式基本没写错。很多次我写完函数直接拿这两个用例一测就能立刻发现符号写反或者log底数写错的问题。6. 信息增益在决策树里的真实工作方式与“偏好取值多”的坑现在你已经能自己算信息增益了接下来要看它在完整决策树算法里是怎么工作的。以ID3算法为例流程是计算当前数据集的熵H(D)。对每个候选特征A计算按A划分后的条件熵再算增益。选增益最大的特征作为当前节点的分裂特征。按该特征的每个取值把数据切成子集对每个子集递归重复1到3步。如果某个子集的类别已经全部一致或者没有特征可用就停止分裂把这个子集标记为数量最多的那个类别。这个流程看起来很顺但实际跑起来会遇到一个经典问题信息增益偏爱取值多的特征。为什么回看条件熵公式按特征A划分后的熵是子集熵的加权平均。特征取值越多子集就越多每个子集里的样本越少就越容易“纯”加权平均熵自然偏低增益虚高。极端情况就是我前面提过的“ID列”每个样本一个唯一ID切出来的每个子集只有一行熵全是0增益直接等于H(D)达到上限。但这样的特征对分类毫无意义。怎么解决有两条路。一条是改用C4.5算法里的增益率Gain Ratio。增益率在信息增益基础上加了一个“惩罚项”GainRatio(D, A) Gain(D, A) / H_A(D)其中 H_A(D) 是特征A本身取值的熵相当于“这个特征自己有多分散”。取值越多、分布越均匀的ID类特征H_A(D)越大分母越大增益率就被压下来了。这是对信息增益偏好的直接修正。另一条路更工程化过滤式特征选择。在建树之前先给每个特征算信息增益设个阈值把增益特别低的排掉。我个人的经验是文本分类场景里特征维度动辄上万如果直接丢给决策树不仅慢而且容易被大量低增益特征干扰。先按信息增益做一轮初筛保留前几百个特征效果通常会稳很多。除了这个经典坑还有一个容易忽略的细节连续特征没法直接用信息增益分裂。信息增益的公式针对的是离散取值的特征如果特征是连续值比如“笔试成绩”是0到100的整数直接把每个数值当一类切出来的子集会碎成渣。C4.5的处理方式是二分法先把连续值排序然后遍历所有相邻值的中间点把数据切成“小于等于阈值”和“大于阈值”两份分别算信息增益取增益最大的那个切分点。我在实际项目里验证过这种做法在数据量上万时效果很不错但也正是这个机制让C4.5建树的速度比ID3慢不少。7. 几个高频疑问和我的个人经验聊到这里我觉得有必要把平时被问得最多的问题集中解答一下。这些问题光看教科书不会想那么细但真上手就会碰到。疑问一信息增益和信息熵到底哪个是“纯度”哪个是“提升”信息熵本身就是纯度/不纯度的度量。熵越大越不纯熵越小越纯。信息增益则是“划分前后纯度的提升量”它是决策树做特征选择时的决策依据。你可以把信息熵理解为“体检指标”信息增益理解为“治疗方案的有效性评估”。疑问二为什么公式里有的地方用log₂有的用自然对数ln取决于底数设定。用log₂单位是bit用ln单位是nat用log₁₀单位是dit。信息的物理含义不受底数影响只差一个常数倍数。机器学习里绝大多数资料用log₂因为决策树和编码理论都建立在二进制基础上但有些统计教材和sklearn内部的mutual_info计算默认用的是自然对数所以你看文档时要注意看它写的单位。用Python算的时候我建议显式写np.log2避免混用ln导致结果对不上。疑问三信息增益是越大越好还是越小越好这要分场景。做决策树分裂时选增益最大的特征做特征筛选时保留增益大的特征扔掉增益小的。但如果你在评估一个模型有没有过拟合增益过大反而要警惕——它可能说明特征跟标签在训练集里产生了“虚假相关”。比如极端情况下拿“候选人的邮件ID”当特征增益爆表但这就是过拟合的铁证。疑问四信息增益是负的怎么办正常情况不会。划分后的加权熵不会大于划分前的熵信息增益始终大于等于0。如果你算出负值大概率是代码写错了概率没归一化或者分组时把空组当成0处理出了bug。我的检查顺序是先看概率和是否为1再看空组的权重是否漏掉最后看log的底数是否统一。我个人的实操体会是单纯背公式很难真正理解这套东西最重要的还是亲手算一遍、写一遍代码。我当初刚开始学决策树时花了整整一个下午用Excel手算一个20条数据的小案例把每个特征的熵、条件熵、增益全部列出来然后才真正明白加权平均的意义。之后再去理解C4.5的增益率、CART的基尼系数就成了一件水到渠成的事。另外如果你想在项目里感受信息增益的实际效果可以用sklearn的mutual_info_classif对真实数据集跑一遍特征排序对比一下你手算的结果。你会发现信息增益高的特征往往就是业务上“最能一锤定音”的那些字段信息增益接近0的特征要么是无关字段要么是取值分布太极端。这个规律在招聘评估、风控评分、营销响应预测里都屡试不爽。