把这门课的账,自己再算一遍
先说结论:这篇挑出的毛病,大部分站得住;但有两处,是帖子自己把话说歪了。我把课程原文(第 07 课 en.md)拉下来,把每个数字重算了一遍。
一、那个没写出来的数,是 1%
「检测 99% 准,你只有不到 1% 可能生病」——这条复算无误,精确值是 0.9804%。但帖子从头到尾没给全条件:光有灵敏度和先验算不出后验,还得有假阳性率。课程原文写的是 P(positive|healthy) = 0.01。我反推了一下:要让后验恰好落在 0.98%,反解出的假阳性率是 0.010004——确认就是这个 1%。
而这个 1% 才是整个例子的魂。真阳比假阳 = 1 : 101。不是检测不行,是病人太稀少,误报的池子比病人的池子大一百倍。帖子这句说得对,但它把最能让人「啊」一下的那个分母藏起来了。
顺带把两个没给的数也补上:垃圾邮件例里 P("lottery"|spam) = 0.05、P("lottery"|ham) = 0.001,似然比 50,推出来 95.54%——帖子给的 95.5% 对。
二、92.5% 这个批评完全站得住,但它自己也要标误差
课程那句「there is a 97% chance B is better」确实在这组数据上不成立。我用数值积分(40 万点梯形)算的精确值是 P(B>A) = 0.92448;十万次蒙特卡洛的标准误 ±0.00084,换十个种子在 0.9231 到 0.9252 之间抖。也就是说:
- 帖子给的 0.9252 只是某一个种子的读数,写成「实测是 92.5%」会被人拿另一个种子反驳;
- 但 97% 与真值差 4.5 个百分点,约 54 个标准误——远超噪声,「97% 不是这组数据的账」这个结论稳如磐石;
- 课程自己的门槛是「P(B>A) > 0.95 才出货 B,落在 0.05~0.95 之间就继续收集」。0.9245 落在继续收集区。按它自己的规则,这组数据判的是「别急着上」。
三、两处帖子说错了,得改回来
第一处:「只需更新两个数」的限定,帖子说「课程三段之后才承认」——落空了。 我查了原文,限定句与口号在同一段,而且在口号前面:原文是「没有共轭先验,你需要蒙特卡洛或变分推断去近似后验;有了共轭先验,你只要更新两个数」。课程没藏,反而写得很直白。这一条批评撤掉。
第二处:MAP 和后验均值不是一回事。 帖子说「先验把你的估计往 0.5 拉了三厘米」。练习 4 问的是 MAP,0.6667 是众数;同一个后验 Beta(9,5) 的均值是 0.6429。0.7 → 0.667 是三厘米,0.7 → 0.643 是五厘米半。若不区分众数与均值,这里就讲糊了。同理,共轭序列的起点是 Beta(1,1)(均值 0.5),课程编为 Day 1,7 正 3 反是 Day 2——帖子叫「第一天」,把起点那一格抹掉了,读者就无法自己核对 0.667 是怎么从 0.5 变来的。
四、tokenizer 那条,帖子说轻了
帖子说「被吃掉的是『a』,分类结果碰巧一致,因为这条证据近乎中性」。这是运气,不是道理。
词表从 44 变 43,改的不只是一个词——它直接改掉了拉普拉斯平滑的分母(total + smoothing × vocab_size),也就是改掉了每一个词的概率。这次只是碰巧没翻车。CountVectorizer 默认的正则 \b\w\w+\b 吃掉的也不只是冠词:单字符 token、数字、以及 split() 会保留的下划线混合串,一并吃掉。在这个 12 句的玩具集上只体现为一个「a」,在真实语料里被吃的可能是「¥」「5」「AI」这类高信息量的东西。
五、顺手核两个外围数字
- 仓库是真的,
rohitg00/ai-engineering-from-scratch,但 star 实测 62,998(2026-10-04),不是 58k。这仓库涨得太快,写死数字会立刻过期,建议改成「6 万 star 量级」。 - 练习 1 的 49.5% 精确复现(一步联合算法与序贯算法完全一致)。但它藏着一个假设:给定真实状态,两次检测的误差互不相关。现实中同一台机器、同一批试剂、同一个操作者,误差是相关的,独立性一破,第二次的增益远小于 50 倍。这个假设帖子没提。
最后
这门课真正的价值,不在那几个数字,在一句话:贝叶斯的整套语法都在回答同一件事——拿到证据之后,你肯把原来的押注挪多少。
挪多少,取决于先验有多偏,而不取决于检测有多准。这句话,比 0.98% 本身更值得记住。