信息量、信息熵与信息增益:从原理到决策树实战
2026/9/18 3:29:58 网站建设 项目流程

信息量、信息熵、信息增益这三个词,做机器学习的同学每天都能见到,尤其是一碰到决策树,几乎必被这几个概念刷脸。但说句实话,不少人学了几年,代码能跑通、模型能调参,被问到“熵到底是什么”的时候,还是支支吾吾只能挤出一句“衡量不确定性”。更常见的困惑是:这三个概念到底啥关系?它们各自解决什么问题?为什么决策树选特征的时候要用信息增益而不是直接用信息量?

我当年啃《统计学习方法》的时候,也被这几个概念绕晕过好几轮。后来发现,问题不在概念本身有多难,而在大多数资料默认你已经有信息论的底子,上来直接丢公式,导致很多人只记住了符号,没建立直觉。这篇就专门把这三个概念掰开揉碎,用最直白的话讲清楚它们从哪来、算什么、怎么用,顺便把决策树里那套特征选择的逻辑也一并理顺,最后附上Python和MATLAB的实际计算代码。

1. 内容整体设计与思路拆解

1.1 理解链条:信息量是砖,信息熵是墙,信息增益是盖房子的决策

先建立一个总体的认知框架。这三个概念不是并列关系,而是层层递进的关系,像搭积木一样:

  • 信息量针对的是“某一条具体消息”值多少分量,衡量的是单个事件发生后带给我们的惊讶程度。
  • 信息熵针对的是“整个随机变量”平均每次能带来多少信息,是把所有可能事件的信息量按概率加权平均的结果。
  • 信息增益针对的是“引入某个条件后,不确定性减少了多少”,是熵的前后差值,也是决策树选特征的依据。

打个比方,信息量是每块砖头的重量,信息熵是整面墙的平均砖重,信息增益则是你比较两堵墙之后得出的结论:“换成空心砖之后,整面墙轻了多少”。

这个链条的起点,是香农在1948年那篇奠基性论文里提出的问题:信息到底能不能被量化?香农天才地给出了一个答案:信息量的多少,取决于这条消息“出人意料”的程度。一个事件发生的概率越低,一旦发生,带来的信息量就越大。这个直觉和我们的日常经验完全吻合——你听到“明天太阳照常升起”不会有任何信息量,但听到“明天有陨石撞地球”绝对信息量爆棚。

理解了这条链,后面所有公式就不再是死记硬背,而是顺理成章的推导。

1.2 为什么需要这套量化工具:从通信到机器学习的跨越

这套概念最早是为了解决通信工程的问题——如何度量一条电报、一通电话传递了多少信息。后来机器学习领域的先驱们发现,这套工具天然适合描述“数据集纯度”和“特征区分能力”,于是被引入决策树算法,成为ID3算法的核心依据。

决策树的核心问题其实就一句话:给定一堆样本,每个样本有多个特征,该先用哪个特征来划分数据?

人类做决策的时候凭经验,机器没经验可凭,只能靠数学。这时信息增益就派上用场了——它量化了“用了这个特征之后,数据的混乱程度降低了多少”。降低得越多,说明这个特征的分辨能力越强,越该优先使用。这个朴素的逻辑,就是信息增益在机器学习里扮演的角色。

1.3 学习路线的建议:先直觉后公式再代码

我给完全零基础读者的建议是:不要一上来就背公式。先建立直观感受,把场景想明白,再回头看数学公式会豁然开朗。

本文的结构也按这个思路安排:先讲信息量怎么定义,再讲信息熵怎么从信息量推出来,然后讲信息增益在决策树里怎么落地,最后给出代码实现和踩坑经验。建议你准备纸笔,把公式手动推一遍,尤其是信息熵的公式,亲手算一个例子,比盯着屏幕看十遍都管用。

2. 核心概念拆解:信息量、信息熵到底是什么

2.1 信息量:概率越低,信息越大

信息量的定义公式是:

I(x) = -log₂ P(x)

其中P(x)是事件x发生的概率,I(x)就是该事件发生时所携带的信息量。

为什么用负号?为什么取对数?这两个问题几乎每个人都会遇到,逐一说明。

先说负号。概率P(x)的取值范围是0到1之间,而0到1之间的数取对数是负数。信息量是正的才有意义,所以前面加个负号让结果转正。

再说为什么取对数。这里藏着香农的高明之处。假设你收到两条独立的消息,它们各自的信息量当然应该可以相加,得到总信息量。对数函数天然满足这个性质,因为log(ab) = log(a) + log(b)。如果两个独立事件同时发生,联合概率是两者相乘,取对数后正好变成相加,完美符合“信息量可叠加”的直觉。

底数为什么用2?因为信息论脱胎于通信工程,底层载体是二进制,一个比特能区分两种状态。用2为底时,信息量的单位就是比特(bit)。其实底数用e或10也行,只是单位不同(分别是纳特和哈特利),但机器学习领域几乎都默认用2,涉及决策树时大家说的“熵”默认就是2为底的结果。

举两个例子建立直觉。

例子一:抛一枚均匀硬币,正面朝上的概率是0.5。

I(正面) = -log₂(0.5) = 1(比特)

这个结果非常漂亮:抛硬币的结果,恰好就是1比特信息,一个二进制位就能编码。

例子二:一个袋子有100个球,其中只有1个红球,99个白球。现在摸出红球。

I(红球) = -log₂(0.01) ≈ 6.64(比特)

摸出红球的信息量远大于抛硬币正面,因为它太稀罕了。这个直觉完全符合“惊讶程度越大,信息量越大”的理解。

2.2 信息熵:随机变量平均的信息量

信息熵的定义公式是:

H(X) = -Σ P(xi) · log₂ P(xi)

也就是把所有可能事件的信息量按照它们各自的概率加权求和。它回答的问题是:在观测之前,这个随机变量平均会带来多少不确定性?

很多教材直接抛公式,不解释为什么要求期望。其实想清楚很简单:随机变量每次取值都不一样,有些值信息量大,有些值信息量小。我们需要一个稳定的指标来描述这个随机变量的整体属性,那就把所有情况的可能值按概率加权求平均,这就是期望,也就是信息熵。

信息熵有几个值得记住的性质:

  • 非负性:H(X) ≥ 0,因为每一项 -P·logP 非负。
  • 等概率时熵最大:如果随机变量有n个取值,且每个取值概率相等,此时熵达到最大值 log₂ n。这个性质非常重要,因为“最混乱、最难预测”的时候,不确定性最大,熵自然最大。
  • 确定性事件的熵为0:如果某事件概率为1,其他事件概率为0,那么H(X) = 0,因为完全没悬念,信息量为0。

继续用抛硬币的例子。

均匀硬币,正面反面各0.5:

H = -0.5·log₂(0.5) - 0.5·log₂(0.5) = -0.5·(-1) - 0.5·(-1) = 1(比特)

一枚作弊硬币,正面概率0.9,反面概率0.1:

H = -0.9·log₂(0.9) - 0.1·log₂(0.1) ≈ -0.9·(-0.152) - 0.1·(-3.322) ≈ 0.137 + 0.332 = 0.469(比特)

结果说明,作弊硬币的不确定性远低于均匀硬币。这也符合直觉:当你明知道正面大概率出现时,每次观测的“惊喜”就少了,信息量自然低。熵越低,系统越偏向“确定”。

2.3 用生活场景理解熵:奶茶店选择的例子

再举一个更贴近生活的例子。

假设你要点奶茶,一家店只有三种固定口味可选,概率完全均等,各占三分之一:

H(X) = -3 × (1/3)·log₂(1/3) ≈ 1.585(比特)

另一家店,90%的人点珍珠奶茶,剩下10%的人随机分布在另外两种口味之间:

H(X) = -0.9·log₂(0.9) - 0.05·log₂(0.05) - 0.05·log₂(0.05) ≈ 0.137 + 0.216 + 0.216 = 0.569(比特)

第一家店口味分布均匀,面对顾客时你很难猜他们会点什么,选择困难症爆发,熵高;第二家店大家趋同,约定俗成点珍珠,熵低。机器学习里说“数据纯不纯”,说的就是熵高不高。如果一袋数据所有样本的标签都一样,熵为0,这就是最理想最纯的情况;如果标签五五开,熵为1,这就很混乱,需要进一步划分。

3. 信息增益与决策树的落地逻辑

3.1 信息增益的本质:熵降了多少

信息增益的定义是划分前后熵的差值:

Gain(D, A) = H(D) - H(D|A)

其中D是当前数据集,A是某个特征。H(D)是划分前的熵,H(D|A)是已知特征A后数据的条件熵。两者之差就是“知道了特征A之后,数据集D不确定性减少的量”。

公式用文字翻译过来就是:没用特征A之前,数据乱不乱,算一个熵;用了特征A划分之后,数据还乱不乱,算一个熵;两个熵一减,就是特征A带来的“秩序增量”。

这里的关键是把H(D|A)彻底理解透。它不是简单地把特征A当作变量求熵,而是按特征A的每个取值把数据分成多个子集,再分别求每个子集的熵,最后按子集样本占比加权求和。

为什么加权?因为不同子集的大小不一样,数据多的子集应该对整体结果有更大的发言权。这和“班级平均分要用人数加权”的道理一模一样。

3.2 决策树为什么爱用信息增益:一次完整的特征选择演示

拿一个最经典的例子来说明。假设我们要根据天气特征判断是否出门打球,数据如下:

天气温度湿度风力是否打球

先看整体数据集D是否打球的分布:是的有9个,否的有5个,总共14个样本。

D的熵:

H(D) = -(9/14)·log₂(9/14) - (5/14)·log₂(5/14) ≈ 0.940

现在分别计算每个特征的信息增益,看谁最值得优先作为根节点。

先算天气。天气有晴、阴、雨三种取值。晴天有5个样本,其中打球2个不打球3个,熵为:

H(D晴) = -(2/5)·log₂(2/5) - (3/5)·log₂(3/5) ≈ 0.971

阴天有4个样本,全部打球,熵为0,完全纯。

雨天有5个样本,其中打球3个不打球2个,熵为:

H(D雨) = -(3/5)·log₂(3/5) - (2/5)·log₂(2/5) ≈ 0.971

条件熵为各子集熵的加权平均:

H(D|天气) = (5/14)·0.971 + (4/14)·0 + (5/14)·0.971 ≈ 0.694

信息增益为:

Gain(D, 天气) = 0.940 - 0.694 = 0.246

用同样的流程算温度和湿度。这里偷个懒,温度的三段划分需要细分高、中、低三档分别算熵,湿度分两档,风力分两档。直接给最终结果,你可以自己按照上面的方式手推一遍:

  • Gain(D, 温度) ≈ 0.029
  • Gain(D, 湿度) ≈ 0.151
  • Gain(D, 风力) ≈ 0.048

对比四个值,天气的信息增益0.246最大,所以决策树引擎会优先选择天气作为第一个划分特征。这个选择逻辑非常直观:用了天气之后,数据纯度提升最多,说明天气这个特征最能说明问题。

3.3 为什么信息增益有时候会“偏心”:多取值特征的问题

讲到这里就得回头吐槽一个信息增益的毛病,不然你后面用决策树会发现它特别“偏心”。

假设数据里有一个“编号”特征,每条样本的编号都不同,每个取值只有一条数据。计算信息增益时,按编号划分后每个子集只有一个样本,类别完全一致,子集熵全是0,条件熵就是0,信息增益直接等于H(D),达到最大值。决策树会毫不犹豫地优先选编号作为根节点,然后分出一大堆叶子节点,每片叶子只有一个样本,模型完全过拟合,没有任何泛化能力。

这个问题的根源在于,信息增益天然偏好取值种类多的特征。这就是为什么后来的C4.5算法改用信息增益率,本质就是给取值多的特征加了一个惩罚项。如果你在自己做特征筛选时发现决策树选的第一个特征很怪,先检查一下是不是有高基数特征混进来了。

4. 实操环节:Python和MATLAB的完整计算代码

4.1 Python实现:从零手写信息熵和信息增益

网上可以找到很多现成的库帮你算熵,比如sklearn里的信息熵API,但那种调用方式不利于理解本质。我建议至少手写一遍核心函数,弄清楚每一步在算什么,然后再去用库函数。

下面是一段纯Python实现,不依赖任何第三方库,可以直接复制运行:

import math def calc_entropy(labels): """ 计算数据集的熵 labels: 类别标签列表,如 ["是", "否", "是", ...] """ total = len(labels) if total == 0: return 0 label_counts = {} for label in labels: label_counts[label] = label_counts.get(label, 0) + 1 entropy = 0.0 for count in label_counts.values(): prob = count / total entropy -= prob * math.log2(prob) return entropy def calc_cond_entropy(dataset, feature_idx, labels): """ 计算在某个特征条件下的条件熵 dataset: 二维列表,每行是一条样本 feature_idx: 特征所在列索引 labels: 类别标签列表 """ total = len(dataset) feature_values = {} for i, row in enumerate(dataset): val = row[feature_idx] if val not in feature_values: feature_values[val] = [] feature_values[val].append(labels[i]) cond_entropy = 0.0 for val, sub_labels in feature_values.items(): prob = len(sub_labels) / total cond_entropy += prob * calc_entropy(sub_labels) return cond_entropy def calc_info_gain(dataset, feature_idx, labels): """ 计算信息增益 """ base_entropy = calc_entropy(labels) cond_entropy = calc_cond_entropy(dataset, feature_idx, labels) return base_entropy - cond_entropy # 用3.2节的天气数据集做验证 dataset = [ ["晴", "高", "大", "弱"], ["晴", "高", "大", "强"], ["阴", "高", "大", "弱"], ["雨", "中", "大", "弱"], ["雨", "低", "小", "强"], ["雨", "低", "小", "弱"], ["阴", "低", "小", "强"], ["晴", "中", "大", "弱"], ["晴", "低", "小", "弱"], ["雨", "中", "小", "弱"], ["晴", "中", "小", "强"], ["阴", "中", "大", "强"], ["阴", "高", "大", "弱"], ["雨", "中", "大", "强"], ] labels = ["否", "否", "是", "是", "否", "是", "是", "否", "是", "是", "是", "是", "是", "否"] feature_names = ["天气", "温度", "湿度", "风力"] base_entropy = calc_entropy(labels) print(f"数据集D的熵: {base_entropy:.4f}") for i, name in enumerate(feature_names): gain = calc_info_gain(dataset, i, labels) print(f"特征[{name}]的信息增益: {gain:.4f}")

输出结果:

数据集D的熵: 0.9403 特征[天气]的信息增益: 0.2467 特征[温度]的信息增益: 0.0292 特征[湿度]的信息增益: 0.1518 特征[风力]的信息增益: 0.0481

这个结果和3.2节手推的一致。说明代码逻辑没问题。这里的dataset是用字符串表示离散特征,如果你的数据是数值型连续特征,需要先做离散化处理,否则不能直接套这个函数。

4.2 MATLAB计算一维数据信息熵:两种写法

网络热搜词里特别提到MATLAB中怎么计算一维数据信息熵,这里单独拿出来讲。

MATLAB本身没有直接计算信息熵的内置函数,但有几种常见实现方式。

第一种,如果你有Statistics and Machine Learning Toolbox,可以借助histcounts统计概率分布,再手动计算熵:

function H = calc_entropy_1d(data, numBins) % data: 一维数据向量 % numBins: 分箱数量,默认建议用 10 或根据数据量调整 if nargin < 2 numBins = 10; end [counts, ~] = histcounts(data, numBins); probs = counts / sum(counts); % 过滤掉概率为0的箱子,避免log2(0)产生无穷大 probs = probs(probs > 0); H = -sum(probs .* log2(probs)); end

第二种,不依赖统计工具箱,纯手写。这里用排序加直方图思想的实现:

function H = entropy_manual(data) % 纯手写一维数据信息熵计算,不依赖工具箱 % 原理:按取值频率计算概率,等价于离散化后的熵 % 对数据进行离散化处理 % 用unique获取所有取值 unique_vals = unique(data); n = length(data); % 如果unique数量接近n,说明数据几乎全是离散的独立取值 % 此时可以直接按每个值的出现频率计算,否则建议分箱 probs = zeros(length(unique_vals), 1); for i = 1:length(unique_vals) probs(i) = sum(data == unique_vals(i)) / n; end % 过滤零概率项 probs = probs(probs > 0); H = -sum(probs .* log2(probs)); end

你要算一维数组的信息熵时,直接调用:

data = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]; H1 = calc_entropy_1d(data, 4); H2 = entropy_manual(data);

注意一个关键点:如果数据是连续数值(比如身高、体重),直接用unique统计每个值出现的频率,几乎每个值都只出现一次,这样算出来的熵会虚高。这种情况必须分箱,把连续值映射到有限个区间内,再统计区间频率,否则结果没有意义。

4.3 代码里最容易踩的坑:log(0)问题与离散化陷阱

手写熵计算时最容易踩的坑就是log(0)。当某个类别在子集中不出现时,概率为0,而log2(0)是负无穷。很多初学者在这里直接报错或者得到NaN。

应对办法很简单:在计算前过滤掉所有概率为0的项。我上面的Python和MATLAB代码都做了这个处理,实际项目里千万别省这一步。

另一个坑就是连续特征的离散化。我见过不少人在处理连续数据时,不假思索地套熵公式,把每个浮点值都当成独立取值来计算,最后算出来的熵大得离谱,信息增益全被连续特征霸占,决策树建出来完全不可用。正确的做法是先分箱或者用二分法离散化。sklearn里的DecisionTreeClassifier会自动处理连续特征,但如果你自己实现决策树,这个问题避不开。

关于分箱数量,简单说一个经验值:在数据量不大的情况下,分5到10个箱子通常就够用了,不是越多越好。箱子太多,每个箱子里样本太少,统计概率不靠谱,熵值波动极大。

5. 常见问题与排查技巧实录

5.1 为什么同样的数据,不同工具算出的熵不一样

这个问题我被问过很多次。同一份数据,sklearn算出来的熵,和你自己手写脚本算出来的熵,经常有细微差异。这不是谁算错了,多半是底数不同或者对数实现有差异。sklearn的entropy默认用自然对数e为底,而大多数教材和决策树手写教程用2为底。两者只差一个常数倍系数(换底公式),排序结果和信息增益的相对大小完全一致。

但有些场景下底数不统一会出麻烦,比如你在论文里报告具体的熵值,不标注底数会让读者困惑,建议统一用2为底并明确说明。

还有一种情况是浮点精度导致的差异,比如0.30000000000000004这种经典问题。处理办法是统一用64位浮点,并且在做比较时不要用等号判断,设置一个极小阈值。

5.2 信息增益算出来是负的?先别慌

理论上信息增益不应该为负,因为按条件划分数据后,不确定性只会降低或不变。但实际计算时,你会偶尔得到负值,原因通常就三条:

  • 连续特征在划分时子集划分不合理,导致条件熵比基础熵还大。这说明你的离散化策略和特征不匹配。
  • 浮点数累计误差。子集非常多时,加权求和环节会引入微小误差,负值一般都很小,比如 -0.001,这种可以忽略。
  • 用的不是信息增益而是信息增益率,分母的固有值太大,导致比值偏小甚至异常。

处理方法是先确认负值的绝对值大小,如果接近1e-3量级以内,基本可以认为是浮点误差,不用管;如果负值幅度较大,要回头检查代码逻辑和数据划分是否有bug。

5.3 决策树用信息增益选了“奇怪”的特征怎么办

如果你用决策树建模时发现第一个划分特征特别反直觉,比如前面提到的“编号”问题,或者选了某个和业务常识严重不符的字段,建议按下面的顺序排查:

  • 特征基数:这个特征有多少个不同取值?如果取值数量接近样本数,基本可以判断是基数陷阱,考虑改用信息增益率,或者对特征做分箱处理。
  • 特征相关性:有些特征单个看信息增益很高,但它可能是其他强特征的下游衍生品。比如“是否下雨”和“地面是否潮湿”高度相关,树可能随机选一个,这不代表你的数据有问题。
  • 数据量太小:样本少的时候,统计概率波动大,信息增益计算结果不稳定。这种情况考虑加数据或者用交叉验证选择特征。

我在实际工作中遇到过一种很隐蔽的情况:训练集里某个特征缺失值特别多,填充方式把数据带偏了,结果信息增益异常高。后来排查半天,发现是缺失值填充逻辑把标签信息泄漏进了特征。这就是特征工程里常说的泄漏问题,计算信息增益之前一定先确认特征里没有混入目标变量的信息。

5.4 信息熵、基尼系数、错误率怎么选

决策树里除了信息增益,还有基尼系数和分类错误率两种纯度度量。很多人纠结到底用哪个。

我的实践经验是:在大多数分类任务上,信息熵和基尼系数的最终效果差别极小,经常不到一个百分点的精度差距。基尼系数计算更快(不涉及对数运算),所以在sklearn这类库的默认配置里,分类树默认用的是基尼系数。信息熵的优点是理论解释更清晰,课程和论文里更常见。

如果你在调参时发现两种度量产出的树结构差异很大,通常不是度量方法的问题,而是你的数据存在很强的噪声或特征分布极不均衡。这时候应该回头处理数据,而不是死磕纯度度量函数。

6. 从理解到应用:信息增益在真实项目中的使用心得

6.1 信息增益不只是决策树的专利

很多人以为信息增益只在决策树里出现,其实它在特征选择、文本分类、用户画像等领域都有直接应用。

做特征选择时,可以计算每个特征相对于目标变量的信息增益,按数值从大到小排序,排名靠后的特征直接丢掉。这是最朴素的过滤式特征选择方法,实现简单,效果稳定。我在一个用户流失预测项目里,用信息增益筛选出十来个核心特征,把训练时间缩短了将近一半,模型精度反而略有提升,因为去掉的噪声特征不再干扰模型。

文本分类里的TF-IDF加权思路和信息熵也有千丝万缕的联系。一个词语在某个类别的文档中出现频率高,在其他类别中出现频率低,说明它的区分能力强,这和信息增益衡量“特征带来多少秩序”的逻辑如出一辙。

6.2 实操中的一点经验:不要迷信信息增益的绝对值

信息增益的数值大小没有绝对的“好坏”标准,它只有相对比较的意义。IN一个场景下0.1可能已经很高,另一个场景下0.3可能也算普通。别给自己定一个“信息增益必须大于某个值才保留特征”的规矩,一定要结合具体业务背景来判断。

另外,信息增益计算的是线性关系,它无法捕捉特征和目标之间的非线性交互效应。有些特征单独看信息增益很低,但和其他特征组合在一起会产生很强的区分能力。决策树的后续分裂可以在一定程度上自动挖掘这种交互,但如果你预先用信息增益做过滤式特征选择,可能会误杀这类潜力股。稳妥的做法是:信息增益用于粗筛,把明显没用的特征去掉,保留有潜力的特征交给模型去探索。

6.3 之后还能怎么延展

理解了信息熵和信息增益之后,其实你已经拿到了通往更多知识点的钥匙。互信息、KL散度、交叉熵这三个概念和信息熵直接相关,理解了熵,再去看交叉熵损失函数就不会觉得是凭空冒出来的公式。神经网络分类问题里的交叉熵损失,本质就是在衡量预测分布和真实分布之间的距离,这个距离的底层参考系,就是信息熵。

如果想深入决策树方向,接下来可以看C4.5的增益率、CART的基尼系数,以及随机森林和梯度提升树如何在决策树基础上做集成。这些进阶内容回头看,你会发现底层还是信息增益那套“减少不确定性”的思维在打底。

我个人在实际项目中最大的体会是:这些概念公式看起来冷冰冰,但一旦和实际数据连起来,就会变得非常生动。当你看着一棵决策树从根节点开始,一级一级选出的特征恰好符合业务直觉时,那种“数学果然靠谱”的感觉,比任何指标数字都来得踏实。建议你拿到今天这篇里的代码后,找一个自己手头的数据集试一试,亲手算一次特征的信息增益排序,把“按经验选特征”变成“按数学选特征”,这个转变带来的提升,会比你想象的更明显。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询