The Ergodicity Game(遍历性游戏)是一个特别适合拿来校正概率直觉的模拟游戏:一枚硬币、两个倍率,就能让“平均赚大钱”和“个人长期亏光”同时成立。如果你正在学概率统计、投资组合、行为金融或者量化风控,我建议先花半小时把这个游戏跑一遍。它可以把“期望值”和“个人真实轨迹”之间的差距,压缩成一个能被反复试验的模型。下面我会按自己实际跑模拟的顺序来拆:先讲规则,再给能复现的代码,然后讲参数判断标准,最后说几个容易踩的坑。
1. 这个游戏到底在模拟什么
1.1 游戏规则:一次下注、两种结果
游戏参数非常少。假设初始本金是 1,每一轮都掷一次硬币:
- 正面:本金乘以 1.5;
- 反面:本金乘以 0.6。
也就是说,赢的时候赚 50%,输的时候亏 40%。每轮概率各 50%。
如果只看单轮期望倍率:
0.5 × 1.5 + 0.5 × 0.6 = 1.05
看起来像“平均每轮赚 5%”。只要轮次足够多,期望收益就会变得非常可观。但这里面的问题在于:期望收益是按很多个平行世界的平均来算的,而一个真实玩家只走其中一条路径。
| 事件 | 概率 | 本金倍数 | 对数增长 ln(倍数) |
|---|---|---|---|
| 正面 | 50% | 1.5 | ≈ 0.4055 |
| 反面 | 50% | 0.6 | ≈ -0.5108 |
后面那个“对数增长”很关键。资产如果是乘法过程,连续多轮之后看的是对数收益的累加,不是百分比收益的直接平均。
1.2 为什么叫“遍历性”
“遍历性”这个词听起来复杂,但它问的是一个很实用的问题:
用很多个平行世界算出来的平均结果,和一个人沿着时间一条路走下去算出来的平均结果,是不是同一个数?
如果两者一样,就说这个量具有遍历性。如果不一样,就是非遍历的。
在这个游戏里,每一轮资金的期望倍率是 1.05。所以从横截面看,第 t 轮所有玩家的平均资金是:
E[W_t] = 1.05^t
但一个典型玩家长期走下来,每轮实际发生的对数增长率是:
0.5 × ln(1.5) + 0.5 × ln(0.6) = 0.5 × ln(0.9) ≈ -0.0527
把对数增长率还原成几何平均倍率:
exp(-0.0527) ≈ 0.9487
也就是说,沿着单条时间线走下去,典型玩家每轮实际是把本金打了大约 0.9487 折。玩 100 轮之后,中位数资金大约只有初始资金的 0.005 倍;玩到 500 轮,中位数已经接近 0。
这就出现了“横截面平均在涨,个人长期典型路径在跌”的现象。资金本身在这个游戏里不具备遍历性。它是最常被拿来演示非遍历性的例子之一,所以很多人把它直接叫做遍历性游戏。
2. 先跑一个最小可复现的模拟
2.1 准备条件:只需要 Python 和 NumPy
本地跑这个模拟不需要 GPU,不需要大型依赖。只要:
- Python 3.8 以上;
- NumPy 1.17 以上。
安装命令:
pip install -U numpyWindows、macOS、Linux 都能跑。普通笔记本跑 10000 条路径、500 轮的模拟,通常几秒到几十秒,取决于机器和内存。
如果机器内存很紧张,可以把路径数降到 5000,或者把轮次降下来。
2.2 最小模拟代码:用对数收益避免溢出
我建议直接用对数收益来写。原因很简单:如果轮次比较长,比如 5000 轮,直接累乘 1.5 或者 0.6 很容易产生巨大的数字或接近 0 的数字,有时候会触发浮点溢出。用对数收益先累加,最后再取指数,更稳。
下面是一段可以直接保存运行的代码:
import numpy as np def ergodicity_game( n_paths=10_000, n_steps=500, win=1.5, loss=0.6, p=0.5, seed=42, ): rng = np.random.default_rng(seed) # 生成所有路径的所有随机事件 u = rng.random((n_paths, n_steps)) # 换成对数收益 log_returns = np.where(u < p, np.log(win), np.log(loss)) # 累加对数收益 log_wealth = np.cumsum(log_returns, axis=1) # 转回真实资金 wealth = np.exp(log_wealth) final = wealth[:, -1] return { "mean_final": final.mean(), "median_final": np.median(final), "fraction_below_1": (final < 1.0).mean(), "max_final": final.max(), "min_final": final.min(), } if __name__ == "__main__": stats = ergodicity_game() for k, v in stats.items(): print(k, v)跑完之后,你会看到几个数字。我实际跑出来的结果大致是:
- 最终资金均值非常大,经常到几百万甚至几十亿;
- 最终资金中位数非常小,500 轮时通常已经在 1e-12 以下;
- 最终资金小于 1 的比例接近 1,也就是说绝大多数路径“亏到零附近”。
这种“均值巨大、中位数接近 0”的组合,就是游戏最核心的现象。
2.3 怎么判断模拟有没有跑出效果
第一次跑通之后,不要只看“没有报错”就结束。判断标准至少要有三条:
- 脚本能正常结束,输出不是空值;
- 中位数明显小于 1;
- 均值明显大于 1,而且远远大于中位数。
如果三个条件都满足,说明模拟已经成功复现了非遍历性。如果均值还不够大,或者中位数还不低,先不要怀疑公式,先检查轮次和路径数是不是太少。
注意:不要用单条路径或者几十条路径的均值去下结论。这个游戏本身就是高方差问题,样本太少时,均值会被少量极端路径影响,结果很不稳定。
3. 参数与公式:把“看着不错”变成“可判断”
3.1 真正决定长期趋势的是对数增长率
把游戏参数抽象一下:赢的时候乘 a,输的时候乘 b,赢的概率是 p。那么:
- 每轮期望倍率:m = p × a + (1-p) × b
- 每轮对数增长率:g = p × ln(a) + (1-p) × ln(b)
- 每轮几何平均倍率:exp(g)
很多人只看第一个数 m。只要 m 大于 1,就会觉得这个游戏“能玩”。但从个人长期路径来看,真正决定典型净值是向上还是向下的,是第二个数 g。
看几个常见参数组合:
| 赢乘数 a | 输乘数 b | 每轮期望倍率 m | 对数增长率 g | 个人长期典型趋势 |
|---|---|---|---|---|
| 1.5 | 0.6 | 1.05 | ≈ -0.0527 | 趋向 0 |
| 1.8 | 0.5 | 1.15 | ≈ -0.0527 | 趋向 0 |
| 1.2 | 0.8 | 1.00 | ≈ -0.0204 | 趋向 0 |
| 1.25 | 0.8 | 1.025 | 0 | 围绕本金随机游走 |
| 1.1 | 0.95 | 1.025 | ≈ 0.0220 | 长期增长 |
前两行很有意思:1.5 和 0.6 的乘积是 0.9,1.8 和 0.5 的乘积也是 0.9。虽然算术期望不同,一个每轮平均涨 5%,另一个每轮平均涨 15%,但个人长期典型增长率完全相同,都是负数。
这说明一个问题:如果一个多轮重复过程会乘到已有结果上,那么只看算术期望很容易高估个人真实体验。
3.2 均值、中位数和典型路径可以差多少
用对数收益的视角能解释得更清楚。假设每轮对数收益的均值是 μ,方差是 σ²。那么:
- 横截面均值:E[W_T] = exp(μT + σ²T/2)
- 典型路径的中位数:约等于 exp(μT)
两者之间的差距是 exp(σ²T/2),会随着轮次 T 指数扩大。也就是说,玩得越久,均值和中位数之间的裂口越大。
在原始参数里,μ 是负数,所以中位数不断下降;σ² 又让均值被极端路径不断拉高。一个非常常见的误判是:我看到均值大幅增长,就觉得大多数人也赚到了钱。实际上,均值可能只被极少数连续赢很多次的人拉起来了,而大多数人的净值已经跌到很低。
3.3 什么条件下非遍历性问题可以被缓解
这个游戏并不是在告诉你“所有风险都不能碰”。它是在告诉你:如果只能一个人连续重复下注、而且每次都是全仓承受乘数变化,那么你的长期增长率是 g,不是 m。
但如果能用某种机制把很多个独立结果同时打包,并且互相分摊盈亏,情况会改变。比如把一笔资金拆成很多份,同时分散到很多个互不相关的独立下注里,组合每轮的结果接近这些下注的算术平均值。这时候组合的时间增长率会更接近 ln(m),也就是正数。
这就是为什么分散化和再平衡在数学上不是“降低收益的保守做法”,而是把横截面平均转化成个人可以实际经历的时间平均的手段。当然,现实中很难找到完全独立、完全同分布的互不相关资产,但这个思路本身非常重要。
4. 从游戏到实际决策:可复用的思考顺序
4.1 先分清加性过程和乘性过程
遍历性问题不是对每个决策都同样严重。遇到加性过程,比如每个月固定存一笔钱,或者固定领工资,单次结果不断加到总结果上,期望值通常更接近个人真实长期体验。
遇到乘性过程,事情就变了。投资组合、交易账户、创业公司的股本、复利增长里的利率,都属于乘性过程。因为上一轮的结果会变成下一轮的本金,所以百分比变化不能直接按算术平均来理解。
判断标准很简单:下一轮的结果是不是由“当前已有结果”乘上一个随机倍率得到?如果是,就要多看一眼几何平均和分位数。
| 过程类型 | 典型场景 | 决策时要更关注什么 |
|---|---|---|
| 加性过程 | 固定工资、固定储蓄 | 单次结果平均值、累计误差 |
| 乘性过程 | 投资、复利、创业股权 | 对数增长率、几何平均、破产概率 |
4.2 用几何平均而不是算术平均做长期判断
实际做判断时,可以用一个很简单的工具:
import numpy as np p = 0.5 a = 1.5 b = 0.6 g = p * np.log(a) + (1 - p) * np.log(b) geometric_mean = np.exp(g) print(geometric_mean) print("典型净值倍数:", geometric_mean ** 10) print("期望净值倍数:", (p * a + (1 - p) * b) ** 10)如果 geometric_mean 小于 1,说明时间拉长之后,个人典型路径会往下走。如果大于 1,说明在“只接受当前趋势”的情况下,长期典型路径才可能增长。
这只是数学关系。真实决策里还会涉及流动性、税费、人生阶段等因素,不能只靠一个几何平均下结论。
4.3 三个需要反复提醒自己的问题
遇到一个看起来平均收益不错、但结果会作用在本金上的方案时,可以问三个问题:
- 这个决定会不会重复很多次?如果只做一次,期望值可能足够了;如果要重复很多年,就必须看复合增长率。
- 每一轮的结果会不会变成下一轮的本金?如果是,用对数增长去算,不要用百分比直接平均。
- 如果连续遇到几次坏结果,会不会导致无法继续?如果会,就要额外关注最大回撤和破产概率,而不只是看平均值。
这三个问题不需要复杂编程,但能避免很多“数值上看着赚、过程上根本扛不到”的判断。
5. 把它变成课堂或团队小活动
5.1 不写代码也能玩的版本
The Ergodicity Game 不只是编程模拟,也可以做成线下教学游戏。
每人初始 100 个筹码。每一轮用硬币或骰子决定结果,正面乘 1.5,反面乘 0.6。玩 20 轮之后,记录每个人的最终筹码数。
然后对比三组数字:
- 全组平均筹码;
- 全组中位数筹码;
- 筹码低于初始值的人数比例。
多数时候,少数连续赢的人会把全组平均值拉高,但大部分人的中位数已经明显低于初始值。这个对比比讲公式更直观。
5.2 复盘时看哪些数字
活动结束后,不要只问“赚了多少”,要多看几个角度:
- 有多少人最终高于初始资金?
- 有多少人最终低于一半?
- 全组平均是不是远高于中位数?
- 如果重来一次,你会不会选择只投一部分资金参与?
最后一个问题能自然引到“仓位管理”。很多人看到 1.5 和 0.6 的第一反应是:只要一直玩,期望就是正的。但实际体验会让他们发现,全仓连续参与的结果很可能不是自己想要的。
5.3 更友好的课堂参数组合
如果担心 20 轮之后大多数人资金都归零,气氛太极端,可以把参数调温和一点。
- 温和参数:赢乘 1.25,输乘 0.8,玩 10 轮。单轮几何平均恰好是 1,所以中位数大致在 1 附近,但依然会出现明显分化。
- 强烈参数:赢乘 1.5,输乘 0.6,玩 20 轮以上。这个参数最能体现均值和中位数的巨大分裂。
也可以先跑温和参数,再跑强烈参数,让参与者自己感受“平均收益好”和“长期体验差”之间的差别。
6. 常见卡点、误区和排查顺序
6.1 模拟结果和理论值对不上
如果你跑出来的均值不够大,或者中位数不够低,先不要怀疑遍历性概念,按顺序排查:
- 轮次是不是太短?低于 50 轮时,现象不一定明显。
- 路径数是不是太少?100 条路径的均值很不稳定,至少用 5000 到 10000 条。
- 随机种子有没有固定?如果不固定,两次结果差异会很大,不利于观察规律。
- 参数是不是写反了?赢乘数和输乘数写反,结果会完全不同。
如果用了 10000 条路径、500 轮,固定 seed 之后还是正常启动,那结果一般都会显示出均值远大于中位数。
6.2 数值溢出或内存不足
- 如果轮次加到 5000 以上,直接累乘 1.5 容易溢出。用对数收益方式可以避开这个问题。
- 如果
n_paths * n_steps太大,比如 10 万条路径乘 1 万轮,会占用大量内存。可以把路径分块循环,或者降低路径数。 - 如果输出出现 nan 或 inf,优先检查输入参数里是否有 0 或负数。乘数为 0 时,对数收益是负无穷,最终资金会直接变成 0,这符合逻辑,但会干扰图表展示。
注意:不要一上来就开“最大规模”炫耀机器性能,先用 10000×500 验证逻辑,再考虑是否需要扩大。
6.3 别把游戏结论推广过头
这个游戏是一个经过简化的教学模型。它能说明“期望收益为正”不等于“个人长期典型收益为正”,但它不能直接被搬来证明某类资产“不能买”或“一定会归零”。
现实里,人们可以调整仓位,可以分散,可以停止参与,可以加入止损,也可以改变每轮暴露的本金比例。游戏中“每轮全仓参与”只是众多可能策略里的一种。
把遍历性游戏当成一个检查工具更合适:当一种结果会复利式地作用在原有结果上时,我要看的不只是单次期望值,还要看几何平均、分位数和最坏情况下的存活概率。真正决定长期体验的,往往是这些更容易被忽略的指标。
跑完这套流程之后,我自己最大的感受不是“均值不能信”,而是“均值要放在正确的流程里才能用”。先判断过程是加性还是乘性,再判断自己能不能通过分散和再平衡把横截面平均变成个人时间平均,最后用对数增长率和分位数去卡边界。The Ergodicity Game 把这一串抽象概念变成了一个半小时就能亲手验证的小实验,值得自己跑一次。