十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

从高中递推数列到马尔可夫链:状态转移矩阵与平稳分布的建模思路

从高中递推数列到马尔可夫链:状态转移矩阵与平稳分布的建模思路 先抛一个明确判断高中里很多“概率递推题”表面是在考数列构造实际上是在考一种更底层的模型——把状态、权重、递推三者写成一个统一形式而它的终点就是马尔可夫链。这类题无论出现在选择填空、概率大题还是压轴题里都不该靠临时背套路来处理因为套路一变就失效了。刷过高中数学概率与数列题的人多少会遇到这种“熟悉又别扭”的题目某个量第 (n1) 项不是只由第 (n) 项决定还要引入另一个状态。题目用一句话描述“从甲状态到乙状态的概率是几”然后就让你求长期占比。于是你开始设未知数、列递推、找不动点最后顺利算出一个好看的分数。但如果你停下来想想会发现自己其实是在做矩阵乘法、在求解特征值 (1) 对应的向量只是题目没有把矩阵两个字写出来而已。这篇文章想做的事是拿“一道由递推题引发的思考”作为线索把高中数学里分散的几个知识点串起来为什么递推系数可以看成权重为什么权重相加为某个常量时有特殊含义为什么一旦这些权重稳定且与“状态”绑定就可以拓展到马尔可夫链我会给一个二元状态的完整推导再把模型拓展到多状态最后用 Python 代码验证结果。读完这篇文章你不仅能重新理解这类题目还能获得一个从“做题”切换到“建模”的支架。1. 这道题真正在考什么这类题目最常见的设置是这样讨论一个对象只有两种状态比如“甲城/乙城”“晴天/雨天”“健康/带病”。每个周期内对象可以在状态之间迁移迁移的概率只依赖于当前状态与更早的历史无关。题目给出条件概率例如“今天晴则明天晴的概率是 (0.8)”“今天雨则明天晴的概率是 (0.6)”然后要求第 (n) 天晴的概率或者长期比例的极限。如果不做抽象你会觉得这是一道“数列题”[ x_{n1}0.8x_n0.6(1-x_n) ]这里把“雨的概率”用 (1-x_n) 替代了因为系统只有两状态。然后化简成[ x_{n1}0.60.2x_n ]接下来可以求通项、求极限。这种方法能够做题但有一个隐患它隐藏了“为什么权重是 (0.8) 和 (0.6)”这个结构问题。很多人做这道题时并不知道这个式子也可以写成[ \begin{pmatrix} x_{n1}\ 1-x_{n1} \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_{n1})等于“上一周期各个状态的概率”分别乘以“对应转移概率”后再相加。这就是加权平均的另一种形式。把握住这一点题目就从“记忆公式”变成了“理解模型”。2. 权重与递推先打通两个概念2.1 从加权平均说起高中第一次接触“权重”通常是在统计与概率里计算平均分时如果不同题目分值不一样就不能把所有分数简单相加再除以题目数而要乘上各自权重。权重越大贡献越大所有权重相加等于 (1)结果才有“平均”的意义。这个看似简单的思想在递推题里经常被忽略。当递推式写成[ a_{n1}p a_nq b_n ]如果 (pq1)且 (a_nb_n1) 或在某种总量守恒的条件下那么 (a_{n1}) 就可以理解为“把上一周期的分布按权重 (p,q) 融合成新的值”。这里 (p,q) 不是随意的系数而是一组权重它们把一个总量拆分到下一步的某一个状态上。很多学生能算出 (p,q) 的值却不知道为什么要保证它们相加等于 (1)。原因很简单如果状态集合是穷尽的那么下个状态必然落在集合内所有去向概率的总和一定是 (1)。违反了这一点总量会莫名其妙增长或消失模型就会失真。2.2 递推关系中的隐藏权重再往深一层看递推式未必只有一个变量的权重。如果有两个状态变量 (a_n,b_n)它们各自向下一状态的演化都可能是“按权重分配”的[ \begin{cases} a_{n1}p_{11}a_np_{12}b_n\ b_{n1}p_{21}a_np_{22}b_n \end{cases} ]这里 (p_{11}) 表示“上一周期为 (a)下一周期仍为 (a)”的权重(p_{12}) 表示“上一周期为 (b)下一周期变为 (a)”的权重。在概率问题里它们就是转移概率。整个式子可以改写成矩阵形式[ \begin{pmatrix} a_{n1}\ b_{n1} \end{pmatrix}\begin{pmatrix} p_{11} p_{12}\ p_{21} p_{22} \end{pmatrix} \begin{pmatrix} a_n\ b_n \end{pmatrix} ]一旦写成这种形式它就不是一个孤立的“数列技巧”而是一类模型。你会看到影响最终结果的不只是某个权重的大小还包括权重之间的相互搭配。这也解释了为什么只看 (a_{n1}0.8a_n0.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_{n1})”就是因为转移概率不依赖 (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_{n1}Tv_n ]两步演化就是[ v_{n2}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_nb_n1 ]于是第 (n1) 年 A 市人口比例由两部分组成今年 A 市人口中留在 A 市的人加上今年 B 市人口中迁到 A 市的人。因此[ a_{n1}0.8a_n0.6b_n ]又因为 (b_n1-a_n)可化简为[ a_{n1}0.8a_n0.6(1-a_n)0.60.2a_n ]同理[ b_{n1}0.2a_n0.4b_n0.4-0.2a_n ]注意真正让这个递推成立的关键是它有两个变量互相补充。只写 (a_{n1}0.60.2a_n) 虽然方便却容易让人忽略矩阵结构。4.2 求通项与长期极限上面的递推式是一个非齐次线性递推。先找不动点。如果长期比例稳定在一个值 (a^*)那么应该有[ a^0.60.2a^]解得[ a^*0.75 ]于是可以构造新数列[ a_{n1}-0.750.2(a_n-0.75) ]这说明 (a_n-0.75) 是公比为 (0.2) 的等比数列。若初始时 A 市人口占比为 (0.5)那么[ a_n0.75(0.5-0.75)\cdot0.2^{n} ]也就是说[ a_n0.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 # 状态0A市 # 状态1B市 # T[next_state, current_state] T np.array([ [0.8, 0.6], # 下一周期在A市 [0.2, 0.4] # 下一周期在B市 ]) # 初始分布A市占0.5B市占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_{n1}T_3v_n ]于是[ v_nT_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_z1 ]对本节的 (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_{n1}Px_n ]6.3 样本模拟大数定律验证矩阵迭代是精确算分布而模拟是随机采样后统计频率。这两种方式应该互相印证。下面代码随机生成 50 万个人每个人的初始选择按均匀分布然后按转移概率模拟 10 周。import numpy as np rng np.random.default_rng(42) N 500000 # 初始选择编号0A, 1B, 2C states rng.integers(0, 3, sizeN) # 概率矩阵按 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(sizeN) # 根据当前状态选择转移列 p_cum np.cumsum(P[:, states], axis0) # 默认保持原状态当随机数越过阈值时更新 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, minlength3) / 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(axis0))这样做的好处是能把算错的风险前置。如果列和不是 ([1,1])说明矩阵写错了或者模型里存在漏掉的状态。第三矩阵方法真正的优势是高维扩展。手算二元问题可以用消元但三元四元甚至几百个状态的模型手工消元几乎不可行。工程实践中更合理的工作流是定义状态空间确定每个状态的转移概率来源写出转移矩阵用线性代数库或矩阵幂工具计算多步转移用特征值分解或线性方程组求解平稳分布把结果可视化并检查合理性。这六步本身就是一种可复用的建模流程值得当成模板收藏。只要题目能抽出“离散时间、有限状态、转移只依赖当前状态”这三个要素这个模板就能套用。第四在数学学习中要重视“通项”与“极限”两条线。通项公式帮助你理解短期演化路径极限分布告诉你长期状态。有时候极限存在但收敛速度很慢有时候前期波动剧烈但极限依然稳定。只看极限会忽略收敛速度只看前几步会误判长期趋势两者互补。9. 总结与后续学习方向回到开头那道题它从两个状态的递推公式出发只经过一次“权重视角”的转换就变成转移矩阵乘法再把状态数从二元拓展到多元就进入马尔可夫链的领域。这个链条基本可以概括为[ \text{递推数列}\rightarrow\text{加权状态转移}\rightarrow\text{转移矩阵}\rightarrow\text{马尔可夫链} ]如果你现在重新做错题可以试着用三个问题检验是否真正掌握这道题定义了哪些状态这些状态是否互斥且穷尽从每个状态出发下一周期流向各个状态的条件概率列出来是否构成一列权重把权重排成矩阵后每一列的和是否等于 1下一步要计算的是 (Tv_n) 还是 (v_n^T T)这三个问题看起来机械却比死记“特征方程构造法”稳定得多。它逼着你回到问题的结构和定义。如果想继续深入建议从三个方向做拓展阅读一是多状态马尔可夫链的平稳分布与特征值的关系二是吸收马尔可夫链与期望步数计算思考“从某个状态出发平均要多久到达某个吸收状态”三是马尔可夫链蒙特卡洛方法看它如何利用长期分布做采样。三者难度递增但共同起点都是这篇短文里的转移矩阵。你甚至可以把经典的高中概率题改写成模拟程序从统计频率和矩阵迭代两个方向分别得到结果。这种对比练习比单纯刷题更能建立对“概率递推”的直觉。
返回列表