深夜的篝火旁,一群朋友玩起了“接力讲故事”:第一个人开口“小明走进了一片森林”,第二个人接上“他遇到了一只正在看手机的兔子”,第三个人补一句“兔子抬头说:你的 Wi-Fi 密码是多少”……每个新句子都会带来或多或少的“惊讶值”。但请注意,整场故事的“总惊讶值”绝不是三个人各自句子的惊讶值简单相加——因为后两句明显搭着前一句的“便车”。你知道了森林背景,再听到“遇到兔子”,惊讶感就打了折扣。 信息论里的熵,衡量的正是这种“平均惊讶值”。而熵的链式法则,就是这场故事会的“记账规则”:整个故事的惊讶总值,等于第一句的惊讶值,加上第二句在已知第一句后的新增惊讶值,再加上第三句在已知前两句后的更新增惊讶值……一层一层加起来,不重不漏。这项看似朴素的规则,是信息论分析复杂系统的地基:无论是语言模型逐词预测、马尔可夫链的熵率计算,还是霍夫曼编码与算术编码的压缩极限,都能从这条“逐句记账”的法则中找到源头。

岗位关联

掌握熵的链式法则,你就拿到了量化与拆解一切“序列信息”的钥匙——语言建模、数据压缩、信息源评估,这些 AI 落地场景的共同底层逻辑,都逃不开这一条“总惊讶值逐层分解”的数学原理。

目录
  1. 可视化演示
  2. 联合熵定义
  3. 条件熵定义
  4. 链式法则推导
  5. 顺序无关性
  6. 马尔可夫熵率
  7. 压缩编码应用
  8. 理论意义
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

展示系统处理流水线、实时性能指标曲线及多方案对比分析,包含数据流转、吞吐延迟监控与方案评估。

本节配有交互动效(进入视口后自动加载,约 3KB)。

系统可视化 处理流程:输入→处理→模型→输出 性能监控:实时指标 P=L×T

联合熵定义

篝火故事会开场前,组织者要统计“整个故事到底有多难猜”。如果把“开头、续写、结尾”这三个句子看作一个整体,那么不同的三句组合各有各的出现概率,有些版本很常见、有些版本很离谱。把所有这些版本的平均惊讶程度算出来,就是联合熵——它度量的是一整个系统的总不确定性。

在信息论里,单个随机变量的熵 H(X) 衡量它的不确定性。当故事由两个变量 X 和 Y 组成时,联合熵 H(X,Y) 就把 X、Y 的所有取值组合 (x,y) 放在一起:如果我们只知道两者的联合概率分布 p(x,y),那么对下一次出现的组合平均会有多惊讶?组合越难预测,联合熵越大。变量的取值顺序无关紧要,关键是“把整个系统当作一个整体来度量”。

假设 X 取值于集合 \mathcal{X},Y 取值于集合 \mathcal{Y},联合分布为 p(x,y)。联合熵的定义是对所有 (x,y) 组合的概率取负对数、加权求和:

联合熵永远不会是负数:概率都落在 0 到 1 之间,负对数为非负,加权平均自然非负。这就好比故事会的“惊讶值账本”上每一笔记录都是正的——一个系统只会带来信息,不会“倒欠”信息。但要注意,这本账的总金额并不是简单地把 X 的熵和 Y 的熵相加,因为前后句子天然有牵挂。至于为什么不能直接加、到底该怎么加,正是链式法则要解决的问题。

H(X,Y)=−∑x∈X∑y∈Yp(x,y) log⁡2p(x,y)\displaystyle H(X,Y) = -\sum_{x \in \mathcal{X}}\sum_{y \in \mathcal{Y}} p(x,y)\, \log_2 p(x,y)
  1. 联合概率 p(x,y)同时观测到事件 x 和 y 的概率。在故事会里,就是“开头是某个句子且续写是另一个句子”在所有回合同事中出现的占比。
    p(x,y)=P(X=x,  Y=y)\displaystyle p(x,y) = P(X=x,\; Y=y)
  2. 自信息 −log₂ p(x,y)单个组合的惊讶值。概率越低,这一组合越出人意料,负对数值就越大;概率为 1 时,惊讶值为 0。
    I(x,y)=−log⁡2p(x,y)\displaystyle I(x,y) = -\log_2 p(x,y)
  3. 双重求和 ΣΣ把 \mathcal{X} 与 \mathcal{Y} 的所有可能组合都遍历一遍,一个也不漏掉。
    ∑x∈X∑y∈Y(⋅)\displaystyle \sum_{x \in \mathcal{X}}\sum_{y \in \mathcal{Y}} (\cdot)
  4. 加权平均每个组合的惊讶值乘以其概率 p(x,y) 再求和,得到的就是“平均惊讶值”,即联合熵。它也可以写成数学期望的形式。
    H(X,Y)=E[−log⁡2p(X,Y)]\displaystyle H(X,Y) = \mathbb{E}\big[-\log_2 p(X,Y)\big]

条件熵定义

故事会进行到一半,观众已经听完了第一句。此时再听第二句,惊讶感会怎样变化?如果第一句是“天空突然下起大雨”,那么第二句“小明撑开了伞”就一点也不意外;可如果第一句是“阳光明媚的清晨”,第二句“小明撑开了伞”就显得有些蹊跷。条件熵衡量的正是:在已知前文 X 的情况下,后续 Y 还剩下多少平均惊讶值。

条件熵的记号 H(Y|X) 中,竖线后面的 X 是“已知条件”,前面的 Y 是“待预测对象”。它不针对某个具体的 x 计算熵(那是另一个概念 H(Y|X=x)),而是对所有可能的 x 按概率加权平均,得到在所有可能条件下 Y 的平均剩余不确定性——也就是“平均条件熵”。

条件熵有一个优雅的性质:信息不会因为知道更多而增加。知道了前文,后续故事的惊讶值只减不增,即 H(Y|X) ≤ H(Y)。这和直觉完全一致:事前你可能觉得“小明撑伞”有点意外,但先听到“下雨”之后,这个续写就变得理所当然。已知条件就像给惊讶值套上了一层过滤网,滤掉了那些已经被预判到的部分。

H(Y∣X)=∑x∈Xp(x) H(Y∣X=x)=−∑x∈X∑y∈Yp(x,y) log⁡2p(y∣x)\displaystyle H(Y|X) = \sum_{x \in \mathcal{X}} p(x)\, H(Y|X=x) = -\sum_{x \in \mathcal{X}}\sum_{y \in \mathcal{Y}} p(x,y)\, \log_2 p(y|x)
  1. 条件分布 p(y|x)已知前文 x 时,下一句恰好是 y 的概率。它是整个条件预测的“底盘”,由联合概率除以边缘概率得到。
    p(y∣x)=p(x,y)p(x)\displaystyle p(y|x) = \frac{p(x,y)}{p(x)}
  2. 单条件熵 H(Y|X=x)固定一个具体前文 x,Y 在只依赖这个前文时的剩余惊讶值。
    H(Y∣X=x)=−∑y∈Yp(y∣x) log⁡2p(y∣x)\displaystyle H(Y|X=x) = -\sum_{y \in \mathcal{Y}} p(y|x)\, \log_2 p(y|x)
  3. 概率加权平均故事会中不同前文出现的频率不同,要把每个前文对应的条件熵按 p(x) 加权求和。
    H(Y∣X)=∑x∈Xp(x) H(Y∣X=x)\displaystyle H(Y|X) = \sum_{x \in \mathcal{X}} p(x)\, H(Y|X=x)
  4. 紧凑合并式把 p(x) 乘进内层求和中,利用 p(x)p(y|x)=p(x,y),得到右边的双重求和形式,这也是最常见的写法。
    H(Y∣X)=−∑x∑yp(x,y) log⁡2p(y∣x)\displaystyle H(Y|X) = -\sum_{x}\sum_{y} p(x,y)\, \log_2 p(y|x)

链式法则推导

现在回到故事会的核心问题:整个故事的“总惊讶值”该怎么拆解?直觉给出的答案是——第一句带来自己的惊讶,第二句在第一句的基础上带来“新增惊讶”,第三句在前两句的基础上带来“更新增的惊讶”……把这些逐层新增的惊讶加起来,就是全部信息量。这个朴素的直觉,在信息论里正是熵的链式法则。

数学上,拆解依赖概率论的乘法规则 p(x,y) = p(x)·p(y|x):联合分布可以分解为一个边缘分布乘以一个条件分布,这恰好对应“先讲第一句、再在已知第一句的前提下讲第二句”。把乘法公式代入联合熵并逐项化简,就能完成证明。

这就是故事会的记账规则:总惊讶值 = 第一句的惊讶值 + 第二句听完第一句后的新增惊讶值 + 第三句听完前两句后的新增惊讶值 + …… 每一句只记“相对已知道部分的新增信息”,前面的内容绝不重复计账。链式法则把一场复杂的故事拆成了一个个清晰的小步骤,这正是它作为“拆解工具”的威力所在。

H(X,Y)=−∑x∑yp(x,y) log⁡2p(x,y)\displaystyle H(X,Y) = -\sum_{x}\sum_{y} p(x,y)\, \log_2 p(x,y)
  1. 概率乘法代入把 p(x,y) 写成 p(x)·p(y|x)。对数把乘法化为加法,得到两项之和。
    p(x,y)=p(x)⋅p(y∣x)  ⇒  log⁡2p(x,y)=log⁡2p(x)+log⁡2p(y∣x)\displaystyle p(x,y) = p(x)\cdot p(y|x)\;\Rightarrow\; \log_2 p(x,y) = \log_2 p(x) + \log_2 p(y|x)
  2. 双重求和拆项负号逐项分配,得到两个独立的双重求和项,各自只含一个变量或一个条件。
    H(X,Y)=−∑x∑yp(x,y)log⁡2p(x)−∑x∑yp(x,y)log⁡2p(y∣x)\displaystyle H(X,Y) = -\sum_{x}\sum_{y} p(x,y)\log_2 p(x) - \sum_{x}\sum_{y} p(x,y)\log_2 p(y|x)
  3. 识别边缘熵第一项中先对 y 求和,\sum_y p(x,y) = p(x),剩下的恰好是边缘熵 H(X)。
    −∑x∑yp(x,y)log⁡2p(x)=−∑xp(x)log⁡2p(x)=H(X)\displaystyle -\sum_{x}\sum_{y} p(x,y)\log_2 p(x) = -\sum_{x} p(x)\log_2 p(x) = H(X)
  4. 识别条件熵第二项正是条件熵 H(Y|X) 的展开式,于是两个变量的链式法则成立。
    −∑x∑yp(x,y)log⁡2p(y∣x)=H(Y∣X)\displaystyle -\sum_{x}\sum_{y} p(x,y)\log_2 p(y|x) = H(Y|X)
  5. 归纳推广到 n 维对 n 个变量的联合分布反复使用乘法公式 p(x₁,…,xₙ) = \prod_i p(xᵢ|x₁,…,xᵢ₋₁),数学归纳法给出一般形式。
    H(X1,X2,…,Xn)=∑i=1nH(Xi∣X1,X2,…,Xi−1)\displaystyle H(X_1, X_2, \ldots, X_n) = \sum_{i=1}^{n} H(X_i \mid X_1, X_2, \ldots, X_{i-1})

顺序无关性

安排故事会的发言顺序时,有人会担心:如果让口才最好的人先讲,故事的总信息量是不是就变了?链式法则给出的答案是:不会。无论谁先谁后,故事总的惊讶值完全不变,变化的只是拆解方式——这就好像同一笔预算,先记收入再记支出,还是先记支出再记收入,总账永远一致。

从链式法则出发,对两个变量 X、Y,既可以先展开 X 再展开 Y,也可以先展开 Y 再展开 X。两条路径殊途同归,都收敛到同一个联合熵:

这个结果揭示了“信息不增原理”的深意:变量之间一旦有关联,就有一部分信息被两个变量“重复表达”了,联合熵因此小于各自熵之和。换句话说,故事的总信息量是故事这个整体说了算的,与谁先开口无关;但变量之间的相关性会决定“重复记账”的幅度,这也正是条件熵存在的意义。

H(X,Y)=H(X)+H(Y∣X)=H(Y)+H(X∣Y)\displaystyle H(X,Y) = H(X) + H(Y|X) = H(Y) + H(X|Y)
  1. 对称展开等价左边路径先对 X 记账、再记 Y 的条件剩余;右边路径先对 Y 记账、再记 X 的条件剩余。两者都由链式法则得到,都等于 H(X,Y),因此互相相等。
    H(X)+H(Y∣X)=H(X,Y)=H(Y)+H(X∣Y)\displaystyle H(X) + H(Y|X) = H(X,Y) = H(Y) + H(X|Y)
  2. 条件熵上界条件作用平均不会增加不确定性,H(Y|X) ≤ H(Y)。把它代入链式法则,得到联合熵的上界不等式。
    H(X,Y)=H(X)+H(Y∣X)≤H(X)+H(Y)\displaystyle H(X,Y) = H(X) + H(Y|X) \leq H(X) + H(Y)
  3. 独立时取等号当 X、Y 相互独立时,p(y|x)=p(y),条件熵退化为边缘熵,不等式变成等式。故事前后两句毫无关联时,总惊讶值恰好是两句话单独惊讶值的简单相加。
    X⊥ ⁣ ⁣ ⁣⊥Y  ⟹  H(Y∣X)=H(Y)\displaystyle X \perp\!\!\!\perp Y \;\Longrightarrow\; H(Y|X) = H(Y)

马尔可夫熵率

故事会还有一种特殊玩法:每位讲者都很“健忘”,只记得紧挨着的上一句话,更早的内容一概不关心。有了这个“健忘规则”,故事的信息结构会大大简化——这正对应信息论中大名鼎鼎的马尔可夫链:下一时刻的状态只依赖当前状态,与更遥远的历史无关。

用条件熵的语言说,马尔可夫性质可以写成 H(Xᵢ|X₁,…,Xᵢ₋₁) = H(Xᵢ|Xᵢ₋₁)。把这一条代入 n 维链式法则,长长的条件前缀被大幅压缩,联合熵变成首项加一串单步条件熵:

“健忘规则”下,故事的信息消耗是匀速的:每一句新增的惊讶值几乎一样,信息量随句数线性增长。这就像一个状态机,每一步都按固定的速率吐出新信息——马尔可夫链的熵率,就是这台“故事机器”的恒定信息流速。

H(X1,…,Xn)=H(X1)+∑i=2nH(Xi∣Xi−1)\displaystyle H(X_1, \ldots, X_n) = H(X_1) + \sum_{i=2}^{n} H(X_i \mid X_{i-1})
  1. 马尔可夫条件替换链式法则里第 i 项的条件集合 X₁,…,Xᵢ₋₁ 被压缩成 Xᵢ₋₁,历史依赖只保留一阶,这正是“健忘规则”的数学表达。
    H(Xi∣X1,…,Xi−1)=H(Xi∣Xi−1)\displaystyle H(X_i \mid X_1, \ldots, X_{i-1}) = H(X_i \mid X_{i-1})
  2. 链式法则代入把替换后的式子代回 n 维链式法则,联合熵只剩一个初始项和 n−1 个相同的单步条件熵项。
    H(X1,…,Xn)=H(X1)+∑i=2nH(Xi∣Xi−1)\displaystyle H(X_1, \ldots, X_n) = H(X_1) + \sum_{i=2}^{n} H(X_i \mid X_{i-1})
  3. 取平均求极限信息论关心“平均每步新增多少信息”,即熵率。对平稳马尔可夫链,所有单步条件熵相等,联合熵除以 n 再取极限,初始项占比消失。
    Hˉ=lim⁡n→∞H(X1)+(n−1) H(X2∣X1)n=H(X2∣X1)\displaystyle \bar{H} = \lim_{n \to \infty} \frac{H(X_1) + (n-1)\,H(X_2 \mid X_1)}{n} = H(X_2 \mid X_1)
  4. 实际求解步骤先求出马尔可夫链的稳态分布 π(求解 π = πP 的线性方程组),再按稳态分布对每个状态的条件熵做加权平均,就得到熵率 H̄ = Σₓ π(x)·H(转移分布 | x)。
    Hˉ=∑xπ(x) H ⁣(转移分布∣x)\displaystyle \bar{H} = \sum_{x} \pi(x)\, H\!\big(\text{转移分布}\mid x\big)

压缩编码应用

假设你想把故事会听来的故事原封不动转述给没来的朋友。聪明的做法不是把每一句话逐字重发,而是只说“相对上一句新增了什么变化”。朋友手里握着前文这张“底牌”,你只需要报增量——这恰恰是条件编码的思路,也是链式法则在数据压缩中的灵魂。

链式法则告诉我们:带记忆的信息源,其总熵等于各条件熵之和。而香农第一定理保证,任何无损压缩算法的平均码长都不可能低于这个总熵。于是链式法则直接给出了压缩的下界:如果前文已经提供了大量信息,后续符号的条件熵就很小,用很少的比特就能编码它。反过来看,那些“不用重复描述”的部分就是冗余,条件编码正是在系统地消除冗余。

霍夫曼编码和算术编码是两种经典实现。霍夫曼编码按符号概率分配码长:概率大的符号用短码、概率小的用长码,平均码长被证明夹在熵和熵加 1 比特之间。算术编码更进一步,把整个消息映射为 [0,1) 区间内的一个实数,编码长度可以无限逼近熵极限。两者遵循的是同一个原理——给条件概率大的符号分更短的码:

压缩本质上是在“追着条件熵跑”:上下文越丰富、预测越准,条件熵越小,编码就越省。英文文本的单个字符熵并不低,但加上前后文之后,条件熵可以降到很低的水平——这也是文本压缩率能远高于“按字符均匀分布”估算值的原因。故事转述的聪明办法,正是链式法则在工程世界里的直接回响。

H(X)  ≤  ℓˉHuffman  <  H(X)+1\displaystyle H(X) \;\leq\; \bar{\ell}_{\text{Huffman}} \;<\; H(X) + 1
  1. 平均码长 ℓ̄每个符号编码长度按概率取期望,它是衡量压缩效率的核心指标。
    ℓˉ=∑xp(x) ℓ(x)\displaystyle \bar{\ell} = \sum_{x} p(x)\, \ell(x)
  2. 熵下界任何唯一可译码的平均码长都不小于信源的熵,这是所有压缩方案共同的天花板。
    ℓˉ≥H(X)\displaystyle \bar{\ell} \geq H(X)
  3. 霍夫曼上界霍夫曼编码是最优前缀码,它的平均码长至多比熵多 1 比特。
    ℓˉHuffman<H(X)+1\displaystyle \bar{\ell}_{\text{Huffman}} < H(X) + 1
  4. 条件熵版本对条件分布做编码时,平均码长满足同样的不等式。链式法则的意义在于:把总压缩任务按条件逐层分解,每一层都逼近自己的条件熵,总码长就能逼近总熵——这正是上下文建模(如算术编码中的条件概率估计)的理论依据。
    H(Y∣X)  ≤  ℓˉY∣X  <  H(Y∣X)+1\displaystyle H(Y|X) \;\leq\; \bar{\ell}_{Y|X} \;<\; H(Y|X) + 1

理论意义

把故事会放大到任何真实系统:一段语音、一帧图像、一篇文本、一条基因序列……它们都是由大量相互关联的随机变量组成的。熵的链式法则提供了一把标准的“拆解手术刀”:总能先把系统拆成“第一块”和“剩余部分”,再把剩余部分拆成“第二块”和“更剩余的部分”,如此一层层拆下去,直到每一块都小到可以单独分析。

这个分解框架的第一个价值,是给出复杂系统信息量的严格表达式——只要知道每一层的条件分布,总不确定性就是这些条件熵之和。第二个价值,是帮助工程师定位建模重点:条件熵最大的环节,就是预测最不确定的环节,也是改进模型最值得投入的地方。第三个价值,是为跨领域提供统一语言:NLP 中的“下一个词预测”、推荐系统里的“下一行为预测”、压缩算法中的“下一个符号编码”,本质都是链式法则展开后的某一环条件熵。

从篝火旁的小游戏到现代 AI 的大模型,熵的链式法则始终是那把“把大象装进冰箱”的钥匙:面对再复杂的系统,都可以拆成一步步“在已知条件下新增的信息”。理解了这一点,你就掌握了理解和量化一切不确定性的基本功——这也是为什么它被称为信息论中“最朴素也最强大”的定理之一。

H(X1,…,Xn)=H(X1)+H(X2∣X1)+H(X3∣X1,X2)+⋯+H(Xn∣X1,…,Xn−1)\displaystyle H(X_1, \ldots, X_n) = H(X_1) + H(X_2|X_1) + H(X_3|X_1,X_2) + \cdots + H(X_n|X_1,\ldots,X_{n-1})
  1. 逐层展开项每一项都以前面所有变量为条件,反映“在已有信息之上新增的不确定性”,相邻两项共享同一套条件前缀递推关系。
    H(Xi∣X1,X2,…,Xi−1),条件前缀逐项生长\displaystyle H(X_i \mid X_1, X_2, \ldots, X_{i-1}),\quad \text{条件前缀逐项生长}
  2. 顺序任意、前缀一致展开时可以任意选择变量顺序(如先 X₃ 再 X₁),但第 i 项的条件集合必须恰好是所选顺序中排在它前面的那些变量,否则等式不成立。
    H(Xπ(1))+H(Xπ(2)∣Xπ(1))+⋯\displaystyle H(X_{\pi(1)}) + H(X_{\pi(2)}\mid X_{\pi(1)}) + \cdots
  3. 与机器学习联系训练语言模型时最小化的交叉熵损失,本质上是在估计条件熵 H(Xᵢ|X₁,…,Xᵢ₋₁);把所有位置的损失加起来,就是对整个序列联合熵下界的逼近。
    L=1N∑i−log⁡2pθ(xi∣x<i)  ≈  Hˉ序列\displaystyle \mathcal{L} = \frac{1}{N}\sum_{i} -\log_2 p_\theta(x_i \mid x_{<i}) \;\approx\; \bar{H}_{\text{序列}}

AI 应用场景

语言模型的“下一个词预测”

阶段:模型预训练与目标函数设计

解决的问题:传统 N-gram 语言模型要么忽略远距离依赖,要么因为组合爆炸无法计算长文本的概率。链式法则把整句概率严格分解为逐词条件概率的乘积,让模型只需要回答一个局部问题:“给定前面所有词,下一个词最可能是谁?”全局的序列建模由此转化为可以并行训练的局部预测任务。

具体案例:训练 GPT 风格的大语言模型时,目标函数正是对每句话做链式法则展开:让条件概率 P(wₜ|w₁,…,wₜ₋₁) 最大化。训练语料的平均负对数似然(交叉熵损失)就是对条件熵 H(wₜ|wₜ₋₁,…,w₁) 的估计,模型越好,这个值越接近理论熵。工程师通过观察训练损失与理论熵的差距,判断模型容量是否还有提升空间。

马尔可夫链熵率评估信息源

阶段:数据分析与特征工程

解决的问题:如何量化一个序列数据源(传感器信号、网络流量、用户行为轨迹)的“信息密度”?传统做法用方差或峰值衡量波动,无法回答“平均每一步产生多少真正的新信息”这一根本问题。用马尔可夫链建模序列,再用链式法则推导出的熵率公式,就能得到以比特为单位的单位步长信息产出速率。

具体案例:在 IoT 场景下,运维团队从设备状态转移矩阵出发,迭代求解稳态分布,再按稳态分布对各状态的条件熵加权,得到系统的熵率。若熵率接近 0,说明数据高度可预测,压缩缓存可以非常激进;若熵率偏高,说明数据随机性强,需预留充足的带宽与存储。这个指标直接指导了采集频率与存储策略的制定。

上下文感知的无损压缩

阶段:数据存储与传输优化

解决的问题:通用压缩算法(如 gzip)没有充分利用领域先验,压缩比有限。链式法则给出的洞察是:对文本、基因序列、图像像素等强相关性数据,只要建模一个“预测器”来减小条件熵,就能大幅逼近压缩极限。编码器不再从零描述每个符号,而是只描述“相对于上下文的增量”。

具体案例:基因测序数据的 FASTQ 压缩场景中,先用参考基因组作为上下文,再对每条 read 与参考序列的差异(错配、插入、缺失)做算术编码。由于差异的条件熵远低于原始碱基的熵,压缩比可比通用工具提高 5-10 倍,这正是条件熵原理在生物信息领域的具体落地。

Python 演示

python57 行
import math def entropy(probs):    """Compute entropy in bits for a probability list."""    return -sum(p * math.log2(p) for p in probs if p > 0) def build_joint(px, py_given_x):    """Build joint distribution from marginal p(x) and conditional p(y|x)."""    joint = {}    for x, px_x in px.items():        for y, pyx in py_given_x[x].items():            joint[(x, y)] = px_x * pyx    return joint def joint_entropy(joint):    """Joint entropy H(X, Y)."""    return -sum(p * math.log2(p) for p in joint.values() if p > 0) def conditional_entropy(joint, py_given_x):    """Conditional entropy H(Y|X) by definition."""    return -sum(p * math.log2(py_given_x[x][y])                for (x, y), p in joint.items() if p > 0) def markov_entropy_rate(transition):    """Solve stationary distribution then compute the entropy rate."""    states = list(transition.keys())    pi = {s: 1.0 / len(states) for s in states}    for _ in range(200):        pi = {s: sum(pi[p] * transition[p][s] for p in states) for s in states}    rate = sum(pi[s] * entropy(list(transition[s].values())) for s in states)    return rate, pi if __name__ == "__main__":    # Relay story: weather X determines Xiaoming's activity Y    px = {"sunny": 0.4, "rainy": 0.6}    py_given_x = {        "sunny": {"park": 0.75, "home": 0.25},        "rainy": {"park": 0.08, "home": 0.92},    }    joint = build_joint(px, py_given_x)    hx = entropy(list(px.values()))    hxy = joint_entropy(joint)    hy_x = conditional_entropy(joint, py_given_x)    print("H(X)       = %.4f bit" % hx)    print("H(Y|X)     = %.4f bit" % hy_x)    print("H(X,Y)     = %.4f bit" % hxy)    print("H(X)+H(Y|X)= %.4f bit" % (hx + hy_x))    print("chain rule :", abs(hxy - hx - hy_x) < 1e-9)     # Two-state weather Markov chain entropy rate    transition = {        "sunny": {"sunny": 0.8, "rainy": 0.2},        "rainy": {"sunny": 0.4, "rainy": 0.6},    }    rate, pi = markov_entropy_rate(transition)    print("entropy rate = %.4f bit/step" % rate)    print("stationary   =", {k: round(v, 4) for k, v in pi.items()})
目的:用故事会的“天气决定出门方式”联合分布验证链式法则 H(X,Y) = H(X) + H(Y|X),再用晴雨两状态马尔可夫链计算熵率,演示从边缘/条件分布到联合熵、再到熵率的完整数值流程。
  1. joint[(x, y)] = px_x * pyx用概率乘法公式 p(x,y)=p(x)·p(y|x) 由边缘分布和条件分布构造联合分布,这正是链式法则推导的起点。
  2. return -sum(p * math.log2(p) for p in joint.values() if p > 0)按定义直接计算联合熵,对每个组合的自信息按概率加权求和。
  3. for (x, y), p in joint.items()同时解包联合分布中的取值组合与概率,是遍历二维概率表的 Python 惯用写法。
  4. return -sum(p * math.log2(py_given_x[x][y]) ...)直接用条件概率 log 项求和,得到条件熵 H(Y|X),无需先算联合熵再相减。
  5. pi = {s: sum(pi[p] * transition[p][s] for p in states) for s in states}反复迭代 π = πP 求解稳态分布,200 轮后收敛到马尔可夫链的平稳分布。
  6. rate = sum(pi[s] * entropy(list(transition[s].values())) for s in states)按稳态分布对各状态的条件熵加权平均,得到熵率 H̄ = Σπ(x)H(转移分布|x)。
  7. print("chain rule :", abs(hxy - hx - hy_x) < 1e-9)用浮点容差验证链式法则是否成立,数值上验证理论公式。

常见误区

误区联合熵不就直接把每个变量自己的熵加起来吗?总信息量当然等于各部分之和,所以 H(X,Y) 应该就等于 H(X) + H(Y)。

正解链式法则告诉我们 H(X,Y) = H(X) + H(Y|X),而条件熵满足 H(Y|X) ≤ H(Y),所以联合熵通常严格小于两熵之和,只有 X、Y 完全独立时才相等。就像故事会里,第二句总是搭着第一句的铺垫,必然有一部分信息被“提前透露”了——总惊讶值绝不可能是两句单独惊讶值的简单相加。

为何常见:单个变量的自信息对独立事件具有可加性,初学者很容易把“独立事件自信息相加”错误推广为“任意两个变量的熵相加”,忽略了变量之间可能存在的相关性。

误区条件熵就是把两个变量换个位置嘛,H(Y|X) 和 H(X|Y) 应该是一样的数。

正解两者的“已知条件”和“待预测对象”刚好互换,含义完全不同。已知天气再预测今天出门与否,与已知出门与否再反推天气,两者剩余的惊讶值没有理由相同,只有 H(X)=H(Y) 的特例才可能相等。故事会上,“听完第一句后第二句还剩多少惊喜”和“听完第二句后第一句还剩多少惊喜”显然是两回事——你知道了后文,不代表你猜得出前文。

为何常见:联合熵 H(X,Y) 是对称的,这种对称性容易让人误以为一切相关的信息量都对称,却忽略了条件熵本质上是一个“有方向”的量。

误区先展开 X 再展开 Y,和先展开 Y 再展开 X,得到的数应该不一样吧?毕竟条件概率是有方向的。

正解链式法则是“同一总量的不同拆法”:H(X)+H(Y|X) = H(X,Y) = H(Y)+H(X|Y),两条路径严格相等,总信息量由联合分布唯一决定,与记账顺序无关。H(Y|X) 与 H(X|Y) 数值不同是事实,但它们分别搭配了不同的边缘熵 H(X) 和 H(Y),组合起来的总和恰好一致——就像同一笔钱,先记工资再记花销,与先记花销再记工资,总额一分不差。

为何常见:看到 H(Y|X) ≠ H(X|Y),就误以为“拆法不同结果就不同”,忽略了链式法则中的两个分解项是配套出现的,各自搭配不同的“首项”。

误区链越长信息越多,所以马尔可夫链的“熵”也是越来越大的,熵率自然也跟着涨。

正解链式法则逐项叠加的是“每步的条件熵”。对平稳马尔可夫链,所有步的条件熵都相同,因此总熵确实随步数线性增长,但总熵除以步数后的熵率是常数——信息量在累积,信息“速率”却恒定。这就像匀速行驶的车,总里程一直在增加,速度表上的数字却一动不动。

为何常见:把“总熵”(累计量)和“熵率”(速率)混为一谈,本质上是单位混淆:一个带 /步 的量,和一个不带单位的累积量,被当成了同一回事。

面试题

Q1. 关于联合熵与边缘熵的关系,下列说法正确的是?

单选题 · easy

  • A.联合熵恒等于两个边缘熵之和
  • B.联合熵恒不超过两个边缘熵之和← 正确答案
  • C.联合熵恒不小于两个边缘熵之和
  • D.联合熵与边缘熵没有任何关系

答案:B。由链式法则 H(X,Y)=H(X)+H(Y|X),又因为条件熵 H(Y|X)≤H(Y),所以 H(X,Y)≤H(X)+H(Y),等号仅在 X、Y 独立时成立。A 只在独立时正确,C 方向完全反了,D 明显不对。这个故事会里“两句相互搭台”的直觉,就是条件熵比边缘熵小的原因。

Q2. 条件熵 H(Y|X)=0 意味着什么?

单选题 · easy

  • A.已知 X 后,Y 的取值完全确定← 正确答案
  • B.已知 Y 后,X 的取值完全确定
  • C.X 与 Y 相互独立且分布相同
  • D.X 与 Y 的联合熵也等于零

答案:A。H(Y|X)=0 表示在知道 X 的条件下,Y 不再有任何不确定性,即 Y 是 X 的确定性函数。B 描述的是 H(X|Y)=0 的情形;独立时 H(Y|X)=H(Y) 而非常数 0;D 也不对,因为 X 自身可能仍有熵,联合熵仍可为正。就像听完“下雨”这个前文,第二句“撑伞”完全不意外。

Q3. 若随机变量 X 与 Y 相互独立,则 H(Y|X) 等于?

单选题 · easy

  • A.H(Y),因为 X 不提供关于 Y 的信息← 正确答案
  • B.H(X),因为两者的熵必然相等
  • C.0,因为整体信息已经全部确定
  • D.H(X,Y),因为联合等于条件

答案:A。独立时条件分布 p(y|x)=p(y),条件熵退化为边缘熵 H(Y)。条件本身不携带 Y 的任何信息,所以“剩余惊讶”就是 Y 原有的全部惊讶。B 把两个边缘熵强行画等号没有依据;C 是“完全确定”才有的情况;D 把联合熵和条件熵混为一谈。

Q4. 下列哪个是两变量链式法则的正确表达式?

单选题 · mid

  • A.H(X,Y) = H(X) + H(Y|X)← 正确答案
  • B.H(X,Y) = H(X) − H(Y|X)
  • C.H(X,Y) = H(X) + H(X|Y)
  • D.H(X,Y) = H(Y) − H(X|Y)

答案:A。链式法则的本质是把联合熵分解为边缘熵加上条件熵,A 正确。B、D 把减法当成加法,熵是平均惊讶值,信息只会累积不会相抵;C 重复对 X 取熵又加一个 X 的条件熵,两项的和既不是联合熵也没有对应含义。记住故事会“首句惊讶 + 续句条件惊讶”的记账逻辑即可。

Q5. 关于链式法则的展开顺序,下列说法正确的是?

单选题 · mid

  • A.展开顺序不同会得到不同的联合熵
  • B.顺序只改变分解方式,不改变总量← 正确答案
  • C.必须先展开熵值较大的那一个变量
  • D.展开顺序必须与变量下标完全一致

答案:B。H(X,Y)=H(X)+H(Y|X)=H(Y)+H(X|Y),两条路径都等于同一个联合熵,顺序无关。A 把“分解项不同”误当成“总量不同”;C、D 都是对链式法则没有必要的额外限制。就像一笔账先记哪一项,最终总额不变。

Q6. 平稳马尔可夫链的熵率等于什么?

单选题 · mid

  • A.初始状态 X1 自身的熵 H(X1)
  • B.跨多步的条件熵 H(Xn|X1)
  • C.单步转移条件熵 H(Xn|Xn−1)← 正确答案
  • D.各个状态熵的简单算术平均值

答案:C。熵率是联合熵除以步数后的极限。对平稳马尔可夫链,链式法则展开后除第一项外所有条件熵都等于 H(Xn|Xn−1),除以 n 取极限后初始项消失,只剩单步条件熵。A 是初始不确定性而非稳态速率;B 跨步条件熵通常更大;D 忽视了转移结构,正确做法是按稳态分布加权。

Q7. 当 H(X,Y) = H(X) 时,可以推出什么?

单选题 · hard

  • A.X 与 Y 相互独立且分布完全相同
  • B.Y 是 X 的一个确定性函数← 正确答案
  • C.X 是 Y 的一个确定性函数
  • D.X 与 Y 的联合分布恰好为均匀

答案:B。由链式法则 H(X,Y)=H(X)+H(Y|X),要与 H(X) 相等必须 H(Y|X)=0,即给定 X 后 Y 完全确定,Y 是 X 的确定性函数。C 恰好反过来,那是 H(X|Y)=0 的情形,会推出 H(X,Y)=H(Y);A、D 都保证不了条件熵为零。

Q8. 关于条件熵的性质,下列说法正确的有?

多选题 · mid

  • A.条件熵 H(Y|X) 恒不超过 H(Y)← 正确答案
  • B.条件熵 H(Y|X) 恒不小于 H(Y)
  • C.独立时 H(Y|X) 恰好等于 H(Y)← 正确答案
  • D.条件熵 H(Y|X) 恒等于 H(X|Y)

答案:AC。条件作用平均只会减少不确定性,A 正确、B 错误;独立时条件不提供任何信息,C 正确;H(Y|X) 与 H(X|Y) 一般不相等,D 错误。这四句话是条件熵最经典的交叉陷阱,用“听完前文后惊讶感只会降低”这个直觉就能区分。

Q9. 关于马尔可夫链的熵率,下列说法正确的有?

多选题 · mid

  • A.熵率表示每步新增的平均信息量← 正确答案
  • B.平稳链的熵率等于单步条件熵← 正确答案
  • C.熵率数值随链长增加而持续增大
  • D.熵率可由链式法则推导得出← 正确答案

答案:ABD。熵率的定义就是单位步数新增的平均信息量,A 正确;平稳马尔可夫链每步条件熵都相同,B 正确;C 把总熵和熵率混为一谈,速率是常数;D 正确,熵率正是链式法则展开后取极限的结果。可以用“匀速行驶的车:里程涨、速度不变”来记忆。

Q10. 关于 n 维链式法则的推广,下列说法正确的有?

多选题 · extreme

  • A.联合熵等于各项条件熵的总和← 正确答案
  • B.展开顺序改变但总和保持恒定← 正确答案
  • C.变量独立时退化为各熵之和← 正确答案
  • D.展开时只能从第一个变量开始

答案:ABC。n 维链式法则 H(X₁,…,Xₙ)=ΣᵢH(Xᵢ|X₁,…,Xᵢ₋₁),A 正确;与二维一样顺序任选,只要第 i 项的条件前缀与所选顺序一致,总量不变,B 正确、D 错误;独立时所有条件熵退化为对应边缘熵,C 正确。这一题考察的是把二维直觉正确推广到 n 维,并理解“前缀一致性”这个唯一约束。