预注册就一件事:在看到结果之前,把「什么算成功」写死。 听起来是形式主义,实际上它是唯一能防住一类特定错误的工具 —— 那类错误的特征是你永远不会察觉自己犯了, 因为每一步看起来都很合理。
不是防止你说谎,是防止你诚实地骗自己。典型过程:
| 步骤 | 你当时的想法 | 实际发生了什么 |
|---|---|---|
| 1 | 「先跑跑看」 | 没有成功标准 |
| 2 | 「这个数字不太好,可能样本不够」 | 继续跑,等一个好数字 |
| 3 | 「换个切法试试」 | 切出十几个子集 |
| 4 | 「这个子集很漂亮!」 | 在噪声里挑了最大的那个 |
| 5 | 「找到 edge 了」 | 找到的是挑选过程本身 |
每一步都符合直觉,合起来产出一个假发现。而且你会真心相信它 —— 因为你没有在任何一步撒谎。
有一轮分析里,我们切了十二条线 × 前后两半 = 24 个子集,然后报告了好看的那些。 当时就在文档里写了一句警告:「除了一个 z=3.28 之外,其余 z 值全在 1.2–1.9 之间 —— 这是假设生成,不是结论。」
写下这句话花了十秒钟,但它让后来的人(包括我们自己)知道那批数字不能直接拿去下注。 这就是预注册思路的最小可用版本:把「我挑过」这件事记下来。
| 项 | 为什么必须先写 |
|---|---|
| 受判的是哪一条 | 防止事后换马:跑了五条,挑最好的那条来汇报 |
| 通过的门槛是多少 | 防止「差一点,但方向是对的」 |
| 样本量多少才读 | 防止在最好看的那一刻收手 |
| 什么时候读 | 防止反复偷看直到出现好数字 |
| 怎样算失败 | 失败必须和成功一样明确 |
| 落笔时间 | 让「先写还是后写」变成可验证的事实 |
我们那份被判死的预注册写了四条门槛:毛超额 ≥ 某个算出来的成本线、 显著性 z ≥ 2.0、赢过同期三个空模型、前后两半样本同号。 四条全部在读数发生七天前冻结。
「毛超额 ≥ 4%」这种门是拍脑袋。正确的门是从成本反推出来的:
而且预注册里要预先写好门会怎么变。我们那份写了一条: 「若实测滑点 > 0 则门相应抬高」。后来实测滑点是 +0.8pp, 门就自动从 1.45pp 抬到 2.25pp —— 这是条款触发,不是事后改判据。
那个 1.45pp 是「1.75 的费减掉 0.30 的返利堆叠」。 而那 0.30pp 的返利,最后一分钱都没到账。
把它加回去,真实的门应该是 1.75 + 0.8 = 2.55pp。 也就是说,我们在算门的时候,先把一笔还没到手的钱花掉了。
规矩成本线里只许放已经确认会发生的项。 这个错误的方向永远是让门变低,所以它不会被自己发现。
我们那份预注册的开头,逐字写着这句话:
翻译成大白话:受判的那条线,是在偷看了近四分之一样本、 而且部分因为它当时领先才被选中的。
这是个真实的污点。我们把它写在文件第一段,而不是藏起来。理由:
| 结果 | |
|---|---|
| 没有预注册 | 污点存在但不可见,事后谁都说不清 |
| 假装干净的预注册 | 污点被掩盖,比没有更糟 |
| 承认污点的预注册 | 污点变成一个可以讨论的量 |
一份承认了污点的预注册,仍然远强于一份没有预注册。 因为它至少让读者能问:「这个污点有多大?会不会大到推翻结论?」 而这个问题只有在污点被写下来之后才问得出口。
预注册真正起作用的时刻,是数据出来、而你不喜欢它的时候。
我们那条线的终读:门 2.25pp,读数 +1.56pp;门 z≥2.0,读数 z=1.62 —— 两条 FAIL。 但另外两条判据是 PASS(赢过三个空模型、前后两半同号)。
只看 PASS 的那两条,很容易得出「有边,只是不够大」的结论。 判据 1 和 2 的全部作用,就是拦住这个结论。
① 不抬 z 门(原话:「2 就是 2」) ② 不重开纪元 ③ 数据一条不删。
门是七天前写死的,读数出来时它已经不归你管了 —— 这才是预注册的全部价值。一条线如果非要靠改门才能活,那它本来就没活着; 改门只是把发现死亡的日子往后推,而在这期间它一直在花真钱。
不需要工具链。下次动手前,在记事本上写四行,存下来:
| # | 写什么 |
|---|---|
| 1 | 我判的是哪一条(一条,不是一族) |
| 2 | 攒够多少样本我读一次,读一次 |
| 3 | 达到什么数字算成功(要从成本算出来) |
| 4 | 今天的日期 |
四行,两分钟。它挡不住所有错误,但能挡住最贵的那一类 —— 「我事后觉得这个应该算成功」。
预注册不是为了向别人证明什么,是为了让未来的你没法骗现在的你。 它唯一起作用的时刻,就是数据出来、你不喜欢它、 而那扇门已经不归你管了的时候。