先抛一个明确判断:高中里很多“概率递推题”,表面是在考数列构造,实际上是在考一种更底层的模型——把状态、权重、递推三者写成一个统一形式,而它的终点就是马尔可夫链。这类题无论出现在选择填空、概率大题,还是压轴题里,都不该靠临时背套路来处理,因为套路一变就失效了。
刷过高中数学概率与数列题的人,多少会遇到这种“熟悉又别扭”的题目:某个量第 (n+1) 项不是只由第 (n) 项决定,还要引入另一个状态。题目用一句话描述“从甲状态到乙状态的概率是几”,然后就让你求长期占比。于是你开始设未知数、列递推、找不动点,最后顺利算出一个好看的分数。但如果你停下来想想,会发现自己其实是在做矩阵乘法、在求解特征值 (1) 对应的向量,只是题目没有把矩阵两个字写出来而已。
这篇文章想做的事,是拿“一道由递推题引发的思考”作为线索,把高中数学里分散的几个知识点串起来:为什么递推系数可以看成权重?为什么权重相加为某个常量时有特殊含义?为什么一旦这些权重稳定且与“状态”绑定,就可以拓展到马尔可夫链?我会给一个二元状态的完整推导,再把模型拓展到多状态,最后用 Python 代码验证结果。读完这篇文章,你不仅能重新理解这类题目,还能获得一个从“做题”切换到“建模”的支架。
1. 这道题真正在考什么
这类题目最常见的设置是这样:讨论一个对象只有两种状态,比如“甲城/乙城”“晴天/雨天”“健康/带病”。每个周期内,对象可以在状态之间迁移,迁移的概率只依赖于当前状态,与更早的历史无关。题目给出条件概率,例如“今天晴,则明天晴的概率是 (0.8)”“今天雨,则明天晴的概率是 (0.6)”,然后要求第 (n) 天晴的概率,或者长期比例的极限。
如果不做抽象,你会觉得这是一道“数列题”:
[ x_{n+1}=0.8x_n+0.6(1-x_n) ]
这里把“雨的概率”用 (1-x_n) 替代了,因为系统只有两状态。然后化简成:
[ x_{n+1}=0.6+0.2x_n ]
接下来可以求通项、求极限。这种方法能够做题,但有一个隐患:它隐藏了“为什么权重是 (0.8) 和 (0.6)”这个结构问题。很多人做这道题时,并不知道这个式子也可以写成:
[ \begin{pmatrix} x_{n+1}\ 1-x_{n+1} \end{pmatrix}
\begin{pmatrix} 0.8 & 0.6\ 0.2 & 0.4 \end{pmatrix} \begin{pmatrix} x_n\ 1-x_n \end{pmatrix} ]
这两种写法是等价的,但第二种写法的信息量更大。它直接告诉你:系统里每一列数字才是“权重分配”,第一列由今天晴出发,权重分别流向明天晴和明天雨;第二列由今天雨出发,权重分别流向明天晴和明天雨。每一列的和都必须等于 (1),因为这对应“从当前状态出发,下一周期总要去某个状态”。
所以,这道题真正在考的,不是单纯的等比数列,而是带权重的状态转移。所谓 (x_{n+1}),等于“上一周期各个状态的概率”分别乘以“对应转移概率”后再相加。这就是加权平均的另一种形式。把握住这一点,题目就从“记忆公式”变成了“理解模型”。
2. 权重与递推:先打通两个概念
2.1 从加权平均说起
高中第一次接触“权重”,通常是在统计与概率里:计算平均分时,如果不同题目分值不一样,就不能把所有分数简单相加再除以题目数,而要乘上各自权重。权重越大,贡献越大;所有权重相加等于 (1),结果才有“平均”的意义。
这个看似简单的思想,在递推题里经常被忽略。当递推式写成:
[ a_{n+1}=p a_n+q b_n ]
如果 (p+q=1),且 (a_n+b_n=1) 或在某种总量守恒的条件下,那么 (a_{n+1}) 就可以理解为“把上一周期的分布按权重 (p,q) 融合成新的值”。这里 (p,q) 不是随意的系数,而是一组权重:它们把一个总量拆分到下一步的某一个状态上。
很多学生能算出 (p,q) 的值,却不知道为什么要保证它们相加等于 (1)。原因很简单:如果状态集合是穷尽的,那么下个状态必然落在集合内,所有去向概率的总和一定是 (1)。违反了这一点,总量会莫名其妙增长或消失,模型就会失真。
2.2 递推关系中的隐藏权重
再往深一层看,递推式未必只有一个变量的权重。如果有两个状态变量 (a_n,b_n),它们各自向下一状态的演化都可能是“按权重分配”的:
[ \begin{cases} a_{n+1}=p_{11}a_n+p_{12}b_n\ b_{n+1}=p_{21}a_n+p_{22}b_n \end{cases} ]
这里 (p_{11}) 表示“上一周期为 (a),下一周期仍为 (a)”的权重;(p_{12}) 表示“上一周期为 (b),下一周期变为 (a)”的权重。在概率问题里,它们就是转移概率。
整个式子可以改写成矩阵形式:
[ \begin{pmatrix} a_{n+1}\ b_{n+1} \end{pmatrix}
\begin{pmatrix} p_{11} & p_{12}\ p_{21} & p_{22} \end{pmatrix} \begin{pmatrix} a_n\ b_n \end{pmatrix} ]
一旦写成这种形式,它就不是一个孤立的“数列技巧”,而是一类模型。你会看到,影响最终结果的不只是某个权重的大小,还包括权重之间的相互搭配。这也解释了为什么只看 (a_{n+1}=0.8a_n+0.3b_n) 不能理解全部,必须补上另一个状态 (b) 的演化方程。
2.3 权重和为 1 为什么重要
在高中题目里,最常见的权重约束是“每一列的和等于 (1)”。这句话翻译成人话就是:无论现在处于哪个状态,未来总归要落到某个状态,所有去向合计必须占满概率空间。
举个例子,从当前状态 (a) 出发,下一周期可能仍是 (a),也可能转移到 (b),不可能出现第三种去向,所以:
[ p_{11}+p_{21}=1 ]
同理,从当前状态 (b) 出发:
[ p_{12}+p_{22}=1 ]
如果题目给出的数据没有满足这一点,那大概率是设置错了,或者你漏看了一个隐藏在“其他”里的状态。反过来,如果某个递推式不满足列和为 (1),又没有相应的总量变化解释,那就不能代表概率演变。
3. 从加权递推到马尔可夫链
3.1 马尔可夫性:只跟当前状态有关
很多同学听到“马尔可夫链”这几个字就觉得是大学内容,离高中很远。其实它的核心假设非常简单:下一个状态只由当前状态决定,跟更早的历史没有额外关系。这个性质叫马尔可夫性,也叫一阶马尔可夫性。
你可能会质疑:现实中很多过程都有记忆,怎么可能只由当前决定?这其实是模型抽象问题。天气可以用昨天和今天一起预测更准,但如果我们简化成“只依据今天”,依然能得到一个可用的模型;人口迁移、用户状态变化、生物种群演化,很多宏观统计也采用这种简化。
对比前面那道递推题,你会发现马尔可夫性恰好是它成立的前提。题目之所以敢写“由 (x_n) 推 (x_{n+1})”,就是因为转移概率不依赖 (x_{n-1},x_{n-2})。如果状态转移还受前几天影响,那么递推阶数会变高,式子就不会这么简单。
3.2 马尔可夫链的矩阵写法
把多个状态之间的转移概率排成矩阵,就得到马尔可夫链的转移矩阵。以二元模型为例:
[ T = \begin{pmatrix} 0.8 & 0.6\ 0.2 & 0.4 \end{pmatrix} ]
我在这里采用“列向量状态”的表达方式:
- (T_{11}=0.8):今天是状态 A,明天仍是状态 A;
- (T_{21}=0.2):今天是状态 A,明天变成状态 B;
- (T_{12}=0.6):今天是状态 B,明天变成状态 A;
- (T_{22}=0.4):今天是状态 B,明天仍是状态 B。
如果定义:
[ v_n= \begin{pmatrix} a_n\ b_n \end{pmatrix} ]
那么一步演化就是:
[ v_{n+1}=Tv_n ]
两步演化就是:
[ v_{n+2}=T^2v_n ]
所以求第 (n) 步状态,本质上就是反复乘矩阵 (T)。这种写法不会丢失信息,也比单独写一个数列递推更便于拓展到多状态。如果某个教材使用行向量,那么矩阵外形会变成这里的转置形式,但理论结构完全一致。
4. 一个最小模型的完整推导与代码验证
4.1 问题背景与符号约定
为了把抽象概念讲清楚,我用一个“人口迁移”的例子作为最小模型。假设某片区域被分成两座城市 A 和 B,每年都会有人迁居:
- 今年在 A 市的人,明年仍留在 A 市的概率是 (0.8),迁到 B 市的概率是 (0.2);
- 今年在 B 市的人,明年迁到 A 市的概率是 (0.6),仍留在 B 市的概率是 (0.4)。
设第 (n) 年住在 A 市的人占全体比例为 (a_n),住在 B 市的人占全体比例为 (b_n)。因为每个人必须住在其中一座城市,所以:
[ a_n+b_n=1 ]
于是第 (n+1) 年 A 市人口比例由两部分组成:今年 A 市人口中留在 A 市的人,加上今年 B 市人口中迁到 A 市的人。因此:
[ a_{n+1}=0.8a_n+0.6b_n ]
又因为 (b_n=1-a_n),可化简为:
[ a_{n+1}=0.8a_n+0.6(1-a_n)=0.6+0.2a_n ]
同理:
[ b_{n+1}=0.2a_n+0.4b_n=0.4-0.2a_n ]
注意,真正让这个递推成立的关键,是它有两个变量互相补充。只写 (a_{n+1}=0.6+0.2a_n) 虽然方便,却容易让人忽略矩阵结构。
4.2 求通项与长期极限
上面的递推式是一个非齐次线性递推。先找不动点。如果长期比例稳定在一个值 (a^*),那么应该有:
[ a^=0.6+0.2a^]
解得:
[ a^*=0.75 ]
于是可以构造新数列:
[ a_{n+1}-0.75=0.2(a_n-0.75) ]
这说明 (a_n-0.75) 是公比为 (0.2) 的等比数列。若初始时 A 市人口占比为 (0.5),那么:
[ a_n=0.75+(0.5-0.75)\cdot0.2^{n} ]
也就是说:
[ a_n=0.75-0.25\cdot0.2^{n} ]
当 (n\to\infty) 时,(0.2^{n}\to0),所以长期占比收敛到 (0.75)。这个 (0.75) 就是稳态分布。
4.3 Python 验证:矩阵迭代
下面用 Python 直接按矩阵迭代,验证递推与通项结果。这里的代码同时演示了“矩阵作为工具”的优势。
import numpy as np # 状态0:A市 # 状态1:B市 # T[next_state, current_state] T = np.array([ [0.8, 0.6], # 下一周期在A市 [0.2, 0.4] # 下一周期在B市 ]) # 初始分布:A市占0.5,B市占0.5 v = np.array([0.5, 0.5]) print("初始分布:", v) for n in range(1, 8): v = T @ v print(f"第{n}年: A市={v[0]:.6f}, B市={v[1]:.6f}")运行后前几项大约为:
初始分布: [0.5 0.5] 第1年: A市=0.700000, B市=0.300000 第2年: A市=0.740000, B市=0.260000 第3年: A市=0.748000, B市=0.252000 第4年: A市=0.749600, B市=0.250400到第 7 年,A 市比例已经非常接近 (0.75)。这验证了不动点计算的正确性。
这个最小模型告诉我们:权重不是静态权重,而是随着“当前状态分布”一起迭代的。每一年的新分布,都是上一期分布与转移权重做内积的结果。
5. 多状态版本:转移矩阵的幂与平稳分布
5.1 为什么矩阵幂会自然出现
当状态数不止两个,比如三种状态 A、B、C 时,单独的“概率和为 1”无法再直接消元,只能用方程组,或者矩阵。
假设转移矩阵为:
[ T_3 = \begin{pmatrix} 0.5 & 0.4 & 0.2\ 0.3 & 0.4 & 0.3\ 0.2 & 0.2 & 0.5 \end{pmatrix} ]
仍然规定矩阵的第 (j) 列是“当前状态为第 (j) 个状态时,下一周期转向各状态的概率”,因此每列和都为 (1)。设状态分布为:
[ v_n= \begin{pmatrix} x_n\ y_n\ z_n \end{pmatrix} ]
则:
[ v_{n+1}=T_3v_n ]
于是:
[ v_n=T_3^n v_0 ]
这意味着,如果你想一步到位计算第 (n) 期的分布,不需要循环 (n) 次,只需要计算矩阵幂 (T_3^n)。在数学上,矩阵幂可以通过特征值分解来理解;在工程上,可以直接使用线性代数库。
5.2 特征值、特征向量与长期极限
为什么很多马尔可夫链最终会稳定下来?从线性代数角度看,转移矩阵一定有一个特征值为 (1),因为它每列和为 (1),矩阵的每一列之和决定了行和的关系,特征值分解中会出现常数特征方向。
如果其他特征值的绝对值都小于 (1),那么迭代若干步后,对应这些特征值的贡献会指数衰减。剩下的主导项就是特征值 (1) 对应的特征向量,也就是平稳分布。
找一个特征值 (1) 对应的特征向量 (\pi),它满足:
[ T_3\pi=\pi ]
并且概率分布要求:
[ \pi_x+\pi_y+\pi_z=1 ]
对本节的 (T_3),解这个方程组会得到:
[ \pi= \begin{pmatrix} \frac{8}{21}\[2mm] \frac{1}{3}\[2mm] \frac{2}{7} \end{pmatrix} ]
也就是说,长期看三种状态占比会稳定在约:
[ (0.38095,,0.33333,,0.28571) ]
这个结果与初始状态无关,只要矩阵满足不可约、非周期的条件。短期分布则明显依赖初始状态,这也是容易混淆的地方。
5.3 用 NumPy 求矩阵幂和平稳分布
下面用代码演示如何循环迭代多状态系统,并用特征值分解找到平稳分布。
import numpy as np T3 = np.array([ [0.5, 0.4, 0.2], [0.3, 0.4, 0.3], [0.2, 0.2, 0.5] ]) # 初始分布:A、B、C各有1/3 v = np.array([1/3, 1/3, 1/3]) print("初始:", v) for n in range(1, 31): v = T3 @ v if n % 10 == 0: print(f"第{n}期:", np.round(v, 6)) # 输出长期极限 print("循环迭代结果与理论稳态的误差:", np.max(np.abs(v - np.array([8/21, 1/3, 2/7]))))运行结果会显示第 10 期、第 20 期、第 30 期的状态分布向理论值靠拢。最后第 30 期的数值与理论解之间的误差应非常小。
# 方法二:直接求特征值和特征向量,筛选特征值接近1的特征向量 vals, vecs = np.linalg.eig(T3) idx = np.argmin(np.abs(vals - 1)) stationary = vecs[:, idx] stationary = stationary / stationary.sum() print("特征值:", vals.real) print("平稳分布:", stationary.real)这里必须对特征向量做归一化,因为马尔可夫链需要概率和为 (1)。如果转移矩阵定义成行向量形式,则特征向量方向可能相反,需要根据题意调整。
6. 一个马尔可夫链综合例题与模拟验证
6.1 题目设计
把前面的思想放到一个更完整的例子里。某社团成员每周必须在三种活动中选择一种,记为 A、B、C。每个人的选择只取决于上周选择,历史情况不影响下一次选择。概率如下:
- 上周选 A 的人,这周仍选 A、B、C 的概率分别为 (0.5,0.3,0.2);
- 上周选 B 的人,这周选 A、B、C 的概率分别为 (0.4,0.4,0.2);
- 上周选 C 的人,这周选 A、B、C 的概率分别为 (0.2,0.3,0.5)。
第一周所有成员等可能选择 A、B、C,求第 10 周选 A 的同学占比,并求长期占比。
这实际上就是前文的 (T_3) 模型,只是换成了活动选择背景。你可以直接用矩阵迭代求解,也可以用模拟样本近似。
6.2 矩阵求解
转移矩阵为:
[ P = \begin{pmatrix} 0.5 & 0.4 & 0.2\ 0.3 & 0.4 & 0.3\ 0.2 & 0.2 & 0.5 \end{pmatrix} ]
注意这里有轻微背景转换:行表示“这一周的新选择结果”,但我们数据按“上周选 X 后这周选 Y”排列。仍将矩阵写成列向量形式:
- 第一列:上周 A,分别以 (0.5,0.3,0.2) 流向 A、B、C;
- 第二列:上周 B,分别以 (0.4,0.4,0.2) 流向 A、B、C;
- 第三列:上周 C,分别以 (0.2,0.3,0.5) 流向 A、B、C。
所以每列和为 (1)。设第 (n) 周选择 A、B、C 的向量为 (x_n),则:
[ x_{n+1}=Px_n ]
6.3 样本模拟:大数定律验证
矩阵迭代是精确算分布,而模拟是随机采样后统计频率。这两种方式应该互相印证。下面代码随机生成 50 万个人,每个人的初始选择按均匀分布,然后按转移概率模拟 10 周。
import numpy as np rng = np.random.default_rng(42) N = 500000 # 初始选择编号:0=A, 1=B, 2=C states = rng.integers(0, 3, size=N) # 概率矩阵按 P[next, current] 组织 P = np.array([ [0.5, 0.4, 0.2], [0.3, 0.4, 0.3], [0.2, 0.2, 0.5] ]) for week in range(10): # 为每个状态生成一个0到1之间的随机数 u = rng.random(size=N) # 根据当前状态选择转移列 p_cum = np.cumsum(P[:, states], axis=0) # 默认保持原状态,当随机数越过阈值时更新 next_states = states.copy() for s in [1, 2]: mask = (states == s) & (u < p_cum[s, np.arange(N)]) & (u >= p_cum[s-1, np.arange(N)]) next_states[mask] = s states = next_states counts = np.bincount(states, minlength=3) / N print("模拟第10周占比:", counts) # 矩阵精确解 v = np.array([1/3, 1/3, 1/3]) for _ in range(10): v = P @ v print("矩阵迭代第10周占比:", v)由于代码里把矩阵列方向定义为“从旧状态出发转移”,在用np.cumsum时需要小心列索引。这段代码的用途更多是启发思路:随机模拟和大数定律本质上也是在执行“权重转移”。实际工程中更推荐直接用矩阵乘法得到精确概率,只有在模型复杂、状态空间巨大时才考虑蒙特卡洛模拟。
6.4 结果解读
模拟 50 万人第 10 周的占比,理论值应该是矩阵迭代结果,而模拟结果在统计误差内接近它。随着模拟人数增加,误差会以 (\frac{1}{\sqrt{N}}) 量级缩小。这一现象揭示了马尔可夫链与概率统计之间的关系:矩阵的递推描述的是“概率分布”的演化,而模拟描述的是“大量个体频率”的演化,两者在大数定律下一致。
这也是为什么工程中常把用户状态建模成马尔可夫链:当用户数量足够大时,群体状态占比会按照转移矩阵演化,而不必追踪每一个用户的具体路径。
7. 常见认识误区与自查方法
高中乃至入门阶段学习这个主题时,有几个误区反复出现。如果做推导得到的结果和直觉不符,或者最终概率和不为 1,优先检查这几处。
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 第 (n) 期概率相加不等于 1 | 状态未穷尽,或转移概率设置错误 | 检查初始分布和每列权重和 | 用列和等于 1 验证转移矩阵 |
| 递推结果发散、不断增大 | 权重列和不为 1,等价于总量不守恒 | 检查化简前是否丢了另一个状态 | 回到原题重新列状态转移 |
| 读不懂题目里矩阵乘法方向 | 行列向量定义混用 | 明确写清“列向量状态”或“行向量状态” | 统一列和为 1 或行和为 1 |
| 以为平稳分布由初始状态决定 | 混淆短期分布与长期分布 | 用两个不同初始向量分别迭代 | 用矩阵特征值 1 的特征向量求平稳分布 |
| 只记住“求极限就是解不动点” | 不理解不动点代表长期比例 | 写出递推式并检验收敛条件 | 结合特征值判断是否收敛 |
| 马尔可夫链只能处理 2 个状态 | 受到二元消元法影响 | 改用矩阵描述多状态 | 用矩阵幂和特征分解处理高维状态 |
还有一个容易出错点是“权重到底是行和为 1 还是列和为 1”。这个没有绝对标准,取决于你的状态向量是行向量还是列向量。整篇文章使用列向量和列和等于 1,是为了和高中常见的消元思路保持一致。你在参考不同教材或代码时,最安全的做法是先翻译变量,再检查一次矩阵乘法是否符合题意。
另外,不动点存在不代表一定会收敛。如果转移矩阵存在特征值 (-1),系统可能震荡;如果矩阵不可约性缺失,可能存在多个不变子集,平稳分布也会依赖初始状态。高中数学通常不会考这些复杂情形,但做拓展阅读时应该知道边界在哪里。
8. 从数学题到工程模型:几点实践建议
第一,不要把“权重”只理解成百分比。权重可以是非负的转移概率,也可以是某种折扣系数、保留率、迁移率。在工程中,只要存在多个群体或状态在不同桶之间流动,权重矩阵就会自然出现。研究用户从免费版到付费版的转化率、城市人口迁移、库存状态变化,本质上都是同一套“状态 + 权重 + 递推”结构。
第二,写代码验证递推题时不只验证答案,还应该验证“列和是否为 1”。
T = np.array([ [0.8, 0.6], [0.2, 0.4] ]) print("列和:", T.sum(axis=0))这样做的好处是能把算错的风险前置。如果列和不是 ([1,1]),说明矩阵写错了,或者模型里存在漏掉的状态。
第三,矩阵方法真正的优势是高维扩展。手算二元问题可以用消元,但三元四元甚至几百个状态的模型,手工消元几乎不可行。工程实践中更合理的工作流是:
- 定义状态空间;
- 确定每个状态的转移概率来源;
- 写出转移矩阵;
- 用线性代数库或矩阵幂工具计算多步转移;
- 用特征值分解或线性方程组求解平稳分布;
- 把结果可视化并检查合理性。
这六步本身就是一种可复用的建模流程,值得当成模板收藏。只要题目能抽出“离散时间、有限状态、转移只依赖当前状态”这三个要素,这个模板就能套用。
第四,在数学学习中要重视“通项”与“极限”两条线。通项公式帮助你理解短期演化路径,极限分布告诉你长期状态。有时候极限存在,但收敛速度很慢;有时候前期波动剧烈,但极限依然稳定。只看极限会忽略收敛速度,只看前几步会误判长期趋势,两者互补。
9. 总结与后续学习方向
回到开头那道题:它从两个状态的递推公式出发,只经过一次“权重视角”的转换,就变成转移矩阵乘法;再把状态数从二元拓展到多元,就进入马尔可夫链的领域。这个链条基本可以概括为:
[ \text{递推数列}\rightarrow\text{加权状态转移}\rightarrow\text{转移矩阵}\rightarrow\text{马尔可夫链} ]
如果你现在重新做错题,可以试着用三个问题检验是否真正掌握:
- 这道题定义了哪些状态?这些状态是否互斥且穷尽?
- 从每个状态出发,下一周期流向各个状态的条件概率列出来,是否构成一列权重?
- 把权重排成矩阵后,每一列的和是否等于 1?下一步要计算的是 (Tv_n) 还是 (v_n^T T)?
这三个问题看起来机械,却比死记“特征方程构造法”稳定得多。它逼着你回到问题的结构和定义。
如果想继续深入,建议从三个方向做拓展阅读:一是多状态马尔可夫链的平稳分布与特征值的关系;二是吸收马尔可夫链与期望步数计算,思考“从某个状态出发,平均要多久到达某个吸收状态”;三是马尔可夫链蒙特卡洛方法,看它如何利用长期分布做采样。三者难度递增,但共同起点都是这篇短文里的转移矩阵。你甚至可以把经典的高中概率题改写成模拟程序,从统计频率和矩阵迭代两个方向分别得到结果。这种对比练习,比单纯刷题更能建立对“概率递推”的直觉。