跳到主要内容

同一个 4.9,量一年没事,量三十多年就荒谬了

原石
原石

· 阅读约 6 分钟

先贴两行。

from scipy.stats import poisson
poisson.cdf(3, 4.94)   # 0.2699

这是 Viraj Shah 那篇 Burning Man 死亡率分析里最要紧的一行,虽然他自己没把它圈出来。2026 年 Burning Man 死了三个人,有记录以来最多的一年。把年龄标准化后的美国死亡率套到参与者的年龄结构上,一周期望死 4.9 个。实际三例,比期望还低。泊松下尾一算,p 约 0.27。拒绝不了原假设。结论:这个数字不异常。

逻辑干净,数没错。错的是这行代码被拿去问的那个问题有多长。

文章 9 月 27 日发出来的时候,讲到这里就收了。10 月 2 日补了一段:活动总部给了历史参加人数。同一个 4.9 乘回去,整个活动历史上应该死大约 97 个。

expected_total = sum(attendance[y] for y in years) / 70_000 * 4.94  # ≈ 97
# 实际记录 9 例

p 值约 10 的负 30 次方。

同一个模型,同一个假设,换了一把尺子。一边是"三例死亡不奇怪",一边是"这个死亡率荒谬到不可能是真的"。中间没加先验,没搭层次结构,没跑 MCMC。就是把同一份假设,拿去问了一个更长的问题。

我盯这篇就为一件事:那个 p=0.27 的说服力,一半来自模型,另一半来自"只测一年"。而后者才是真正定结论的那个。"拒绝不了原假设"跟"这事没问题",从来是两句话,统计课第一天就该讲。可这篇的全部分歧,都卡在这两句话中间。

12.2 掉到 4.9,砍掉的是年龄

第一步很粗。美国 2025 年第三季度往前十二个月的全因死亡率,每十万人年 909.3。折到 7 万人、一周:

70_000 * 909.3 / 100_000 * (7 / 365)   # 12.21

如果参加者是全美人口的随机抽样,一周得抬出去十二具。实际三十多年一共九例,多数年份挂零。这一步还没做任何校正,就已经很不对劲了。

第二步把年龄结构套上去,拿各年龄组死亡率配参与者的年龄分布:

expected = sum(share[age] * us_mortality[age] for age in bins)   # 4.94

期望从 12.2 掉到 4.9。这一步是对的,也是全文唯一一处认真处理"人群不一样"的地方。但它顺带给了个错觉:好像校准完年龄,剩下那半截差距就归随机波动了。

不是。

年龄标准化只做一件事——假设同年龄的健康程度相同。Burning Man 那批人是什么构成:七成以上回头客,四分之三白人,八成有学士以上学位,三分之一以上年收入十万到三十万美元。这些变量跟健康什么关系,不用统计学教。年龄之外那一大截,大概率全落在一句话里:能被这个活动筛出来的人,本来就更健康。

文章自己承认了,说这是选择偏差,难以用人口变量完全解释。写得对。但我可以说得更重:不是"难以解释",是"不能用变量解释"。你把每个协变量都塞进回归,残差还落在同一个地方。它缺的不是变量,是一个正确的分母。参加者不是全美人口的抽样,你的对照组从第一天起就是错的。

加变量只会让模型看起来更完备,而完备是给审稿人看的,不是给结论看的。

补一句我自己下不了判断的。Pelorus 在评论区说,过往案例里只有一例跟疾病有关,其余是事故、自杀、药物和一起谋杀。如果属实,那 4.9 不但不偏高,可能还偏高——疾病类死亡是被压得最低的那一块,而 4.9 里带着它的权重。选择偏差和死因结构这两件事哪个影响更大,我手里没数据,判不了。这段我没想明白,先放着。

那条把方向算反的评论

Clay Ford 说 p 值方向可能反了:如果原假设死亡率就是 4.9,观察到三例或更多该是 0.72。

1 - poisson.cdf(2, 4.94)   # 0.7156

数学上没错。放在这儿没意义。

我们问的是:真实期望是 4.9 的话,看到三例这么少,奇不奇怪。那得看下尾。把"三例或更多"的概率拎出来,等于在检验一个方向完全相反的备择假设,而这个备择假设本来就没理由信。它只能得到"观察到三例以上非常正常"这种谁都知道的废话。

不是数学错误,是问题错位。这类东西代码里遍地都是:一个函数算得完全正确,算的不是你要的那个问题。

一行的代价

有人看到这儿会说,那得上贝叶斯,或者至少搭个层次模型,把年份之间的相关性也建进去。

不需要。

你缺的那块,全文有个现成来源——总部那边的历史参加人数。拿到,乘一下,三十多年的 p 值就出来了。加先验、搭层次,只会把一个 10 的负 30 次方包装得更漂亮,而它需要的信息,早就躺在一份参加人数统计表里。新加的那层东西得替你省掉麻烦,才配存在。这里省不掉,它就是把答案埋深一点。这就是抽象税。

跟我手头那个玩具引擎一个道理:分母错了,装多贵的引擎跑出来还是错的。

不总结

那篇文章里我最想留下的是那张 95% 置信区间:0.6 到 8.8。作者还特意提醒,这个区间不能读成"死亡数落在其中的概率"。这句话比区间本身值钱。单年 7 万人、三例死亡,样本就这么点,58% 的相对不确定性,一比根号三——这本身就是"别指望单年数据说清什么"的量化版。承认它,比给一个好看的区间有用。

还有个细节:那份人口报告的回复率大约 7%,靠加权校正抽样偏差。也不是什么铜墙铁壁,但对这篇分析够用了。真正把结论掰过来的,是那把更长的尺子。

规则留一条。凡是有人拿一年的数据,给一个已经存在几十年、年年都拿得到数的现象下结论,先问一句:把同一个假设放回去逐年测一遍,成立吗。答不上来的,这个结论先别信。

一个模型能活多久,不看它多精巧,看它敢不敢被放到比今天更长的尺子上量一遍。

原石
原石

把代码当文章写的系统工程师,以源码立论、单线程式拒绝复杂度。

查看主页 →