Day 6 算出了全域 D̂ 和虛無標準誤 SE₀。數字看起來已經很完整,卻還有一種翻車方式:只要拿掉某一題,整個方向就變了。
這種情況在開發集不大時特別常見。有一題剛好正誤各半,能形成很多配對,權重也跟著變大。如果那題的信心模式很特殊,D̂ 可能幾乎由它一手決定。
我不想等審稿時才被問「少這題還成立嗎」,所以直接讓估計器自己回答。
jackknife 的做法很直白。開發集有 Q 題,就重算 Q 次;第 q 次拿掉第 q 題,其餘題目照 Day 6 的配對數權重重新合併:
這裡拿掉的是整道題,不是單條軌跡。同一題的推理軌跡共享提示詞、題目難度和答案空間,彼此高度相關。若每次只刪一條軌跡,會把這些相關樣本誤當成獨立觀測,得到過度樂觀的穩定度。
把 Q 個留一題結果記成 D̂₍₋q₎,jackknife 標準誤為:
拿掉每題後的結果若很接近,SE_J 就小。某幾題一移除便大幅改變估計,SE_J 會直接變大。
先看兩組等權重的題目 D:
穩定組: [ 0.4, 0.5, 0.6, 0.5]
衝突組: [ 1.0, 1.0, 1.0, -1.0]
兩組平均都是 0.5。只報 D̂ 時,它們看起來沒有差別。
穩定組逐題刪除後是:
[0.533, 0.500, 0.467, 0.500]
衝突組則是:
[0.333, 0.333, 0.333, 1.000]
套進 jackknife 公式:
穩定組: D̂ = 0.5,SE_J = 0.041
衝突組: D̂ = 0.5,SE_J = 0.500
負向題一拿掉,衝突組就從 0.5 跳到 1。SE₀ 主要描述題內排名在虛無假設下的抽樣波動,SE_J 則看見題目之間的方向差異。兩者盯的是不同風險。
Day 6 已經替每題存好 D_q、N_q 和 Var₀(D_q),jackknife 可以直接從這些充分統計量計算,不用反覆跑 rankdata。
from dataclasses import dataclass
import numpy as np
@dataclass(frozen=True)
class PooledD:
d_hat: float
se: float
se0: float
se_jack: float
se_floor: float
zeta: float
n_pairs_total: float
n_items: int
def pool_with_uncertainty(
stats: list[ItemStat],
) -> PooledD | None:
if not stats:
return None
n = np.array([s.n_pairs for s in stats], dtype=float)
d = np.array([s.d for s in stats], dtype=float)
var0 = np.array([s.var0_d for s in stats], dtype=float)
total = float(n.sum())
weighted_sum = float(np.sum(n * d))
d_hat = weighted_sum / total
se0 = float(np.sqrt(np.sum(n ** 2 * var0)) / total)
q = len(stats)
if q > 1:
d_leave_one_out = (
weighted_sum - n * d
) / (total - n)
loo_mean = float(d_leave_one_out.mean())
se_jack = float(np.sqrt(
(q - 1) / q
* np.sum((d_leave_one_out - loo_mean) ** 2)
))
else:
se_jack = se0
se_floor = 1.0 / (2.0 * np.sqrt(total))
se = max(se0, se_jack, se_floor)
return PooledD(
d_hat=d_hat,
se=se,
se0=se0,
se_jack=se_jack,
se_floor=se_floor,
zeta=d_hat / se,
n_pairs_total=total,
n_items=q,
)
只有一題時,無法做逐題刪除;程式讓 SE_J=SE₀,至少不會假裝已經檢查過題目間異質性。實驗報告仍應把 n_items=1 明確列出來。
平手修正有個尷尬邊界。若一題的信心全部相同,排名完全不動,Day 6 的虛無變異數會變成 0。多題都出現大量平手時,SE₀ 可能非常小;題目 D 又剛好一致時,SE_J 也可能接近 0。
分母同時縮小,任何一點浮動都會被放大成很誇張的標準化分數。TACT 加上一個只依總配對數 N 決定的下限:
例如總配對數 N=100,最低標準誤是 0.05。即使另外兩個估計只有 0.01 和 0.02,實際使用的 SE 也不會低於 0.05。
這個下限是工程上的保守護欄,不該包裝成唯一正確的統計定理。它的工作很單純:避免退化資料把 z 值吹大。
TACT 最後使用:
這三個數字不是三份互相獨立、可以相加的噪音。它們是針對同一個估計量提出的三種警告:題內虛無波動、題目間異質性,以及退化分母。取平均會把較大的警告稀釋掉,所以這裡直接取最大值。
ζ 保留 D̂ 的正負號。正值表示信心大致和正確性同向,負值表示反向;絕對值則描述目前證據離 0 有多遠。它不是本文要拿來報 p-value 的萬用 z 檢定,後面還會經過門檻和收縮。

圖:同一個全域平均可能遮住子群差異。這不是 jackknife 本身的輸出,而是它要防的同類問題:若拿掉一題或切換群組後方向就改變,只報一個 pooled D 會讓估計看起來比實際更穩。
題目數很少時,留一題結果本來就會粗糙。開發集若只有兩三道可辨識題,SE_J 的數字再精確也補不回缺少的題目多樣性。另一種情況是所有題目都用同一個模板生成,逐題刪除仍可能低估模板層級的相關性;那時應該改成按模板或資料來源分組刪除。
所以我會一起記錄 n_items、總配對數、三種 SE 和是哪一個成為最大值。只留下最終 ζ,日後很難判斷估計到底被哪個警報攔住。
Day 8 會把 ζ 接到顯著性門檻 ν。證據落在死區時,γ 直接留在 0;跨過門檻後也不會立刻全額採用 D̂,還要做 positive-part James–Stein 收縮。
論文預印本:TACT: Trust-Anchored Confidence Tempering for Self-Consistency Voting in Large Language Models