真實世界證據與準實驗工具箱

真實世界證據與準實驗工具箱

一個真實世界證據與準實驗方法的互動教學工具箱。每個方法都有六層,① 是什麼 · ② 互動講解 · ③ 資料分析 · ④ 假設檢驗 · ⑤ 用 AI 強化 · ⑥ 如果……?在下面挑一個方法、用名稱搜尋,或用「怎麼選」走一遍決策樹。

⚠ 本工具所有內建資料皆為純屬虛構的合成示範資料,僅供教學展示。

因果推論 What If:分章讀書筆記

這是 Hernán & Robins《Causal Inference: What If》(免費教科書)逐章重點的雙語讀書筆記,屬於我們自己整理的摘要,並非書本原文;完整內容請看下方連結的免費全書。

🔒 需要密碼

這份筆記僅供本組閱讀,請輸入密碼。

SCCS 自身對照病例系列:分章讀書筆記

這是 Farrington、Whitaker 與 Ghebremichael-Weldeselassie《Self-Controlled Case Series Studies: A Modelling Guide with R》(CRC Press, 2018)逐章重點的雙語讀書筆記,屬於我們自己整理的摘要,並非書本原文。

🔒 需要密碼

這份筆記僅供本組閱讀,請輸入密碼。

名詞表

把工具箱各處的重要名詞集中在一頁。用搜尋直接找到定義;內容會跟著你選的語言顯示。

用「隨機接種提醒」的故事看懂工具變數

我們想知道一個因果問題:去接種疫苗,真的能改善健康嗎? 最直覺的做法是「把有打疫苗的人和沒打的人直接比較」,但這會被誤導。

把名字拆開來看:「工具變數」

變數就是資料裡一欄會變動的量,這裡是「這個人有沒有收到隨機提醒」。工具(instrument)是個比喻: 把它想成一支你能從外面推的槓桿(或撬棒)。推這支槓桿會去動「這個人要不要接種」,但槓桿本身 不會直接碰到健康,它唯一通往健康的路,是透過接種。正因為它只推得動處置、又跟結果沒有別的牽連, 你才能用它把「接種→健康」的因果,從一堆干擾因子底下撬出來。像這支槓桿一樣運作的變數,就叫工具變數。

為什麼不能直接比較?

會主動去打疫苗的人,可能本來就比較注重健康、平常也更願意運動、按時看醫生。 於是他們後來比較健康,不一定是疫苗的功勞,而是「健康意識」這個 看不見的干擾因子同時影響了兩邊。直接比較會高估真正的效果。

工具變數的聰明之處

我們改用一個「外力」當作切入點:衛生單位隨機抽中一些社區,主動寄出免費接種提醒、並安排到府接種服務。 抽中哪些社區是隨機的,跟個人有沒有健康意識無關,但它會推一部分人去接種疫苗。 這個外力就是工具變數(Instrument)。

接種提醒 Z 工具變數 接種疫苗 A 處置 健康變化 Y 結果 健康意識 U 看不見的干擾因子

重點:接種提醒(Z) 只透過 讓人去接種(A) 來影響健康(Y),而且 不 受「健康意識(U)」影響。 因此用它當切入點,就能把 U 造成的汙染繞過去。

三種人

Complier(順從者)

收到提醒就會去接種、沒收到就不會。IV 估計的就是這群人的效果。

Always/Never-taker(一律接受者/一律不接受者)

不管有沒有收到提醒,行為都一樣(本來就會打 / 怎樣都不打)。他們不提供因果資訊。

Defier(反抗者)

收到提醒反而更不去打,我們假設這種人不存在(單調性)。

一句話總結

工具變數法 = 先看「接種提醒推動了多少人去接種」(第一階段), 再看「接種提醒讓健康改變多少」(簡化式),兩者相除就得到 順從者身上的真正因果效應(稱為 LATE)。 想看實際數字,請到 ② 互動講解 與 ③ 資料分析。

動手玩:外力「夠不夠力」會怎樣影響答案

先用白話想一遍

衛生單位寄出接種提醒,我們想用「收到提醒的人後來有沒有比較健康」去回推疫苗到底有沒有效。 但這招好不好用,取決於兩件事:

① 這個提醒有多少「說服力」,能真的說動多少人去打針?
② 我們調查了多少人,問越多人,答案就越穩、越不會亂跳。

下面兩個滑桿就是讓你調這兩件事。我們偷偷把真正的疫苗效果固定成 1.80, 你來看看:自己拉出來的估計,能不能準確抓到這個藏起來的 1.80。

這個提醒夠不夠力
–
估出來的疫苗效果
–
真正答案藏在 1.80
答案的誤差範圍
–

觀察:當「提醒的說服力」很低(沒說動幾個人),就算真正效果固定是 1.80, 你的估計也會劇烈亂跳、誤差範圍超寬,這就是 IV 分析最大的陷阱。

看專有名詞解釋

順從者比例 complier share(first-stage coefficient)

當衛生局隨機寄出提醒,人可以分成幾種。有些人不管怎樣都會去打(always-taker),有些人不管怎樣都不會打(never-taker),這兩種人不論有沒有收到提醒、行為都一樣,所以他們完全無法告訴你「提醒到底有沒有用」。只有「收到提醒才去打、沒收到就不打」的人,才是真正被提醒推動而改變行為的人,他們就是順從者;順從者比例就是這群被推動的人佔全體的多少。這群人是整個方法的引擎:IV 完全靠「觀察這個推力改變了什麼」來反推疫苗效果,所以被推動的人越多,資料能說的就越多。具體說,收到提醒者打針率 58%、沒收到者 52%,這 6 個百分點的差距=順從者比例 0.06,只有 6% 的人在替整個估計出力。它就是第一階段 A = π₀ + π₁·Z + ε 的斜率 π₁,也是後面一切都要除以的分母,所以比例太小就代表估計很不穩、會亂跳(Imbens & Angrist 1994)。

第一階段 F 統計量 first-stage F(instrument strength)

在把提醒當成你的槓桿之前,你得先確認它的推力是真的、不是雜訊,第一階段 F 就是專門做這個檢查的分數。它問:在整份資料裡,提醒到底有沒有把打針率推動到「明顯超過隨機晃動」的程度?F 很大代表推力強而可靠;F 很小代表「提醒會推動打針」這件事很可能只是運氣。這之所以關鍵,是因為每個 IV 答案都要除以工具的強度,第一階段很弱就等於在除以一個接近 0 的數,這既會把誤差範圍撐到很寬,也會把「提醒身上任何小瑕疵」放大成巨大偏誤。例如 F=42 又夠力又安全,F=4 就代表估計不可信、區間大到沒意義。嚴格說它是在檢定 A = π₀ + π₁·Z + ε 裡 π₁ 是不是 0;常見的經驗法則是希望 F>10(Staiger & Stock 1997),而較新的研究(Lee, McCrary, Moreira & Porter;Andrews, Stock & Sun)指出可能需要更高門檻,這也是 Anderson–Rubin 區間等「弱工具穩健」方法存在的原因。

弱工具 weak instrument

弱工具就是「推力太小、根本不夠用」的外力,提醒幾乎改變不了人們會不會去打針,於是可供學習的順從者寥寥無幾。它聽起來無害(「弱工具頂多答案吵一點」),其實是個陷阱:當提醒和打針的關聯很微弱時,IV 估計會不再像乾淨的因果數字,反而偏回它本來要修正的、有混淆的普通比較,有時甚至比不修還糟,同時誤差範圍寬到什麼都說不出來。舉例來說,若提醒只讓打針率動一點點、第一階段 F 只有 3,那就是弱工具,它算出的 IV 數字不該被當成效果報告出去。常見的警示線是 F < 10(Staiger & Stock 1997):偏向那個混淆比較的幅度大約是 1/F,而傳統信賴區間也會失準。對策是換一個真正更強的外力、改用偏誤較小的 LIML,或改用弱工具穩健推論(Anderson–Rubin)。

IV 估計(LATE) local average treatment effect

IV 交給你的數字不是疫苗對所有人的效果,而是「被提醒推去打針的那群人(順從者)」身上的效果,對其他人都不算數。這就是為什麼叫局部平均處置效果,局部於被推動的那群人。它的算法很單純:把「打開提醒時健康變了多少」除以「打針率變了多少」,也就是把推力造成的結果變化,用推力造成的打針變化去縮放。舉例來說,若收到與沒收到提醒者的健康差 0.14、打針率差 0.06,估計就是 0.14 ÷ 0.06 ≈ 2.4。寫成簡式就是 Wald 比值 LATE = Cov(Y,Z)/Cov(A,Z)(Imbens & Angrist 1994)。正因為它只替順從者發言,它通常不是「對所有人」的效果,而且綁定在這個特定提醒上:換個外力會推動不同的一群順從者、可能得到不同的 LATE,所以兩個都完全有效的 IV 研究,可以正當地得出不一樣的數字。

95% 信賴區間 95% confidence interval

「LATE = 2.4」這種單一數字是你的最佳猜測,但換一批人來抽樣,猜測會稍微不同,95% 信賴區間就是這個猜測真實的誤差範圍。把它讀成「資料無法排除的效果大小範圍」:越寬,代表資料越沒把答案釘死。對 IV 來說這比一般分析更重要,因為區間寬窄是由工具強度決定的,弱提醒或順從者少,區間就會變得非常寬,這正是資料在提醒你「別太相信那個點估計」。舉例來說,LATE=2.4、區間 1.1–3.7,表示效果相當明確為正、但大小模糊;若區間是 −1 到 6,那連正負號都看不太出來。課本版的算法是 估計 ± 1.96 × 標準誤,它的意思是「這類區間在重複抽樣下有 95% 機率涵蓋真值」。弱工具下這個保證會失效,所以才偏好不論提醒強弱都有效的弱工具穩健區間(Anderson–Rubin)。

資料分析:跑一次完整的 IV

或 尚未載入資料

程式(SAS · R · Stata):工具變數兩階段最小平方法

出處 — R 使用 AER 套件的 ivreg(),寫法同 AER 官方手冊/vignette 對 ivreg 的示範(公式以 | 分隔內生變數式與工具變數集),並以 summary(diagnostics=TRUE) 取得弱工具第一階段 F 與 Wu-Hausman;Stata 為官方手冊的 ivregress 2sls 搭配 estat firststage;SAS 為 PROC SYSLIN 的 2SLS 標準用法。

這是可直接在可下載的 iv_sample.csv 上完整執行的程式(欄位:health_score_change、vaccinated、vaccine_reminder、age、female、bmi、chronic_conditions、income_band)。

SAS — proc syslin 兩階段最小平方

/* read CSV */
proc import datafile="iv_sample.csv" out=d dbms=csv replace;
    getnames=yes;
run;
/* 2SLS: instrument vaccinated with vaccine_reminder */
proc syslin data=d 2sls;
    endogenous vaccinated;
    instruments vaccine_reminder age female bmi chronic_conditions;
    model health_score_change = vaccinated age female bmi chronic_conditions;
run;

proc syslin 加上 2sls 選項,將 vaccinated 視為內生變數,並以 vaccine_reminder 及外生共變項作為工具變數。

R — AER::ivreg

# instrumental-variables 2SLS with weak-instrument F
library(AER)
d <- read.csv("iv_sample.csv")
fit <- ivreg(health_score_change ~ vaccinated + age + female + bmi + chronic_conditions |
             vaccine_reminder + age + female + bmi + chronic_conditions, data = d)
summary(fit, diagnostics = TRUE)

直線符號 | 之後列出完整工具變數集合;diagnostics=TRUE 會輸出弱工具第一階段 F 值與 Wu-Hausman 檢定。

Stata — ivregress 2sls

* read CSV and fit 2SLS
import delimited "iv_sample.csv", clear case(preserve)
ivregress 2sls health_score_change age female bmi chronic_conditions ///
    (vaccinated = vaccine_reminder)
estat firststage
* ivreg2 (Baum, Schaffer, Stillman) gives richer weak-IV stats

ivregress 2sls 估計模型;estat firststage 給出第一階段 F 值。使用者撰寫的 ivreg2(Baum、Schaffer、Stillman)提供更多弱工具診斷。

這個分析可不可信?六道體檢

工具變數法要成立,得先通過幾道關卡。下面用白話幫你一項一項體檢, 綠燈代表沒問題、黃燈要留意、紅燈代表有狀況。其中一道是「抓包測試」, 不去證明外力合格,而是反過來挑它毛病、試著當場戳破它:戳不破才比較可信。 每張卡片最下面可以展開看「專有名詞解釋」。先到 ③ 資料分析 載入資料,這裡就會自動跑。

(這幾項對應統計上的 A1–A4b 假設,以及一組「工具不等式」否證檢定,但你不用記這些代號,看白話說明就好。)

尚未載入資料,請先到「③ 資料分析」載入或上傳資料。

AI 怎麼幫「工具變數」一把

因果機器學習一次看懂:從平均效果(ATE)到個體化效果(CATE)

超越單一平均效果。傳統方法估的是一個平均處置效果(ATE)。因果機器學習更進一步,瞄準個體化/條件效果(CATE):誰受益、受益多少。Meta-learners(S-/T-/X-/DR-learner)是與模型無關(model-agnostic)的套法,把彈性 ML 放進輔助模型(結果與傾向模型),而因果識別仍靠和本頁相同的假設,無未測混淆、重疊/正性、一致性。對真實世界資料(EHR、登錄)要小心:彈性 ML 能減少模型設定錯誤的偏誤,但救不了未測混淆,而且「預測得準」不等於「因果效果」。本頁 ⑤ 的示範正是這個想法的一個具體案例,用彈性 ML 處理輔助模型,識別仍來自設計。出處:Feuerriegel 等, Nature Medicine 2024;Kaddour 等, arXiv:2206.15475;Li & Chu 主編, Springer 2023。

還記得 ② 互動講解裡那個最大的陷阱嗎?外力(提醒)太弱,答案就會亂跳。 AI/機器學習能在這裡幫上兩個忙,下面我們用同一個疫苗的故事,一步一步看懂。

藥方一:把很多弱外力揉成一個強外力

一通提醒推不動幾個人,但如果手上有很多種小外力(接種提醒、診所傳單、公司提醒、社區廣播…), 每個都弱,AI 能把它們聰明地加起來,合成一個夠力的大外力。

藥方二:讓「外力→打針」這條關係可以彎

有些外力的影響不是一條直線。用直線去抓會抓不到、以為它沒用; 讓 AI 把這條關係「彎起來」,就能抓到直線錯過的力道。

安全帶:交叉擬合(一定要繫)

讓 AI 學這些關係時,有個鐵則:不能拿同一批人的資料既學習又驗證, 否則它會「偷看答案」、給出看似漂亮其實騙人的結果。交叉擬合就是這條安全帶。

藥方一:把很多弱外力合成一個強外力

資料長什麼樣子?看著兩群人「疊加」後分開

每一列是有被推(青)與沒被推(灰)兩群人「傾向去打針」的分布。① 單一弱外力:兩團幾乎完全重疊,光看它幾乎猜不到誰會打針。② 疊加幾個,兩團開始拉開。③ AI 合成十幾個這種弱外力,兩群人就分成清楚的兩團,這時才看得出誰會去打針。那個「分得開」就是強度:很多分不開的弱外力,疊加成一個分得開的強工具。

先用白話想一遍

想像你手上有好幾種推人去打針的小外力,每一種單獨看都太弱 (像 ② 裡那種會讓答案亂跳的弱提醒)。 AI 的做法是:把這些小外力各取一點、聰明地組合成一個全新的「合成外力」。 合成後它變得夠力,答案就穩了。下面拉拉看:

最強的單一外力
–
單獨用最好的那一個
合成後的外力
–
AI 把全部揉成一個
合成後估出的效果
–
真正答案藏在 1.80

觀察:左邊一根根矮柱是每種外力單獨的力道(大多很矮、不及格線 10), 最右邊那根高柱是 AI 合成後的外力,通常遠遠超過及格線。 用單一弱外力估,誤差範圍寬到沒法用;用合成外力,範圍收窄、穩穩罩住 1.80。

看專有名詞解釋

候選工具變數 candidate instruments

白話:一堆各自太弱、單獨用不上的小外力。
定義:一組「看起來都合格」(影響處置、且只透過處置影響結果)的變數,但每個單獨的第一階段 F 都偏低。
為什麼重要:單一弱工具會讓 IV 估計亂跳;很多弱工具正確地合起來,卻可能有真正的力道。
例子:離診所的距離、簡訊提醒、小額補助、診所營業時段,每個都讓打針率動一點點。
公式:工具群 Z₁, Z₂, …, Z_k,各自的 π₁ 都很小。

工具合成(MLIV) instrument synthesis / machine-learned IV

白話:讓 AI 把很多弱外力「揉」成一個強外力。
定義:用機器學習一次吃進所有候選工具來預測處置,再把這個預測值當成單一、較強的合成工具。
為什麼重要:它能從一堆弱工具裡救出力道,但一定要搭配交叉擬合(見藥方三),否則預測會「偷看」結果、把偏誤帶回來。
例子:模型用四個外力預測每個人的打針傾向,這個預測分數就成了新工具。
公式:Â = f(Z₁…Z_k)(由 ML 學)再以 Â 當工具;對 Â 的第一階段 F 會高很多。

第一階段 F/弱工具/95% 信賴區間 recap

第一階段 F(柱子高度)=工具強度,門檻 10;低於 10 =弱工具。95% 信賴區間=誤差範圍。(完整定義見 ②「看專有名詞解釋」。)這裡重點在看圖:每個單一外力的柱子都很矮(弱),但合成後的工具柱子越過了 10。

藥方二:讓第一階段「可以彎」

資料長什麼樣子?是一座山丘,不是一道斜坡

這裡的外力是「離今天快打巡迴車的距離」(橫軸),縱軸是打針率。灰點明顯排成一座山丘: 兩端最低、中間最高。琥珀色虛線是直線的看法,幾乎平的,「看不到」關係; 青色曲線是可彎的看法,緊貼著山丘。當真實形狀是彎的,就得讓模型彎。

先用白話想一遍

換一個外力:「離今天的快打巡迴車有多遠」。它的影響不是直線, 太近沒感覺、太遠也懶得去,只有中間某個甜蜜點最會推人去打針(像一座小山丘)。 如果你硬用一條直線去描述它,會發現幾乎抓不到關係,誤以為這個外力沒用; 但讓 AI 把這條關係彎成山丘的形狀,力道一下子就出來了。按下面看結果:

看專有名詞解釋

彈性/非線性第一階段 flexible / non-linear first stage

白話:讓「外力→處置」這條關係,照資料真正的形狀去彎,而不是硬畫一條直線。
定義:第一階段改用彈性學習器(多項式、樣條、樹模型、神經網路)取代直線回歸。
為什麼重要:若真實關係是彎的(一座山丘),直線會「看不到」關係、把工具的力道整個丟掉。
例子:離快打車的距離在中間「甜蜜點」最有效,曲線抓得到,直線抓不到。
公式:A = f(Z) + ε(f 彈性),取代 A = π₀ + π₁·Z。

禁止迴歸 forbidden regression

白話:把彎好的預測值「直接」塞回第二階段,這個看似聰明、其實錯誤的捷徑。
定義:用在同一批資料上配好的非線性/ML 第一階段,把配適值塞進 2SLS,此時 2SLS 的代數不再成立,偏誤就跑進來。
為什麼重要:因為模型「偷看」了同一批人,會把他們的雜訊(與混淆)一起帶下去,給你一個看似很有把握、其實偏掉的答案。
例子:配一個隨機森林第一階段、把預測塞進第二階段 → 估計黏回那個被汙染的未校正數字。
解法:絕不直接塞,一定搭配下面的交叉擬合。

藥方三・安全帶:為什麼一定要「交叉擬合」

資料長什麼樣子?一條把雜訊也背起來的扭動曲線

綠色虛線是真正的平滑關係。每個點是我們實際手上的少數幾個人,因為運氣,各自偏離真相一點點。 如果讓彈性 AI 在同一批人身上又學又評分,它會畫出那條紅色扭動線,穿過每一個點、 把他們的運氣都背起來。這裡看似完美,換一批新人就垮。交叉擬合逼 AI 用從沒看過的人來評分,它就作弊不了。

用白話講這條鐵則

AI 很會「背答案」。如果讓它用同一批人的資料既學習「外力→打針」這條關係、 又拿這條關係去估效果,它會把這批人的運氣(雜訊)也一起背起來, 給你一個看似很準、其實騙你的結果(這就是「禁止迴歸」陷阱)。
交叉擬合的做法很單純:把人分成幾組,永遠用「別組」的資料學關係、 再套到「這組」沒看過的人身上。AI 沒機會偷看,結果才可信。

怎麼做:交叉擬合的輪替

現場示範:同一個 AI 模型,兩種用法

下面用一個真正會「背答案」的樹模型(random forest)當第一階段, 在同一筆資料上跑兩次,唯一的差別是有沒有繫安全帶。按鈕跑跑看 (要訓練模型,約需幾秒):

看專有名詞解釋

過度配適 overfitting

白話:模型在「背答案」,把訓練那批人各自的運氣(雜訊)都記了起來。
定義:彈性模型連雜訊都配進去(不只訊號),所以樣本內超好看、換新資料就垮。
為什麼重要:過度配適的第一階段會「製造假力道」,餵進 IV 後把效果拉向被汙染的未校正估計。
例子:一條穿過每個點的扭動曲線,這裡看似完美,換一批人就崩。
徵兆:樣本內誤差極小、留出(沒看過的人)誤差很大。

交叉擬合 cross-fitting / out-of-fold prediction

白話:永遠用「別組」的人學關係,再套到「這組」沒看過的人,模型就沒機會偷看。
定義:把樣本切成 K 折;每一折都用其他折配模型、對留出的那折做預測,再把這些「折外預測」拼起來。
為什麼重要:它消掉過度配適/禁止迴歸的偏誤,讓你能安全地在第一階段用 ML,這是雙重/去偏機器學習(DML)的核心步驟。
例子:切 5 折;第 1 折的人,由只用第 2–5 折訓練的模型來評分。
公式:對第 k 折的 i,預測=f₋ₖ(Zᵢ)(不含第 k 折所訓練的模型)。

雙重/去偏機器學習 double / debiased machine learning (DML)

白話:一套「讓你放心用強力 ML 去處理輔助部分、又能保住因果估計的正確性」的配方。
定義:用 ML+交叉擬合估計輔助函數(如第一階段),再把它們塞進一個Neyman 正交的動差條件,使 ML 的小誤差幾乎不動到最終估計。
為什麼重要:它把 ML 的彈性與「有效的信賴區間」結合起來,是用豐富資料做 IV/效果估計的現代做法。
例子:ML 第一階段+交叉擬合,把 IV 估計拉回真值 1.80 附近、誤差範圍可用。
關鍵:正交性+交叉擬合 ⇒ 對輔助模型誤差穩健。

把所有做法擺在一起比

同一個疫苗故事,換個招式:用「滿 65 歲」這條線(RDD)

在 ①–⑥ 我們用「隨機接種提醒」當工具。這裡換一種設計:假設有一個免費接種計畫, 只開放給滿 65 歲的人。一跨過這條生日線,資格就突然改變,這個「跳一下」, 讓我們可以不需要任何隨機工具,就讀出疫苗的效果。

把名字拆開來看:「斷點回歸」

回歸(regression)=用資料配出一條最能描述「結果如何隨某個分數變化」的線(或曲線), 這裡是健康分數如何隨年齡變化。斷點(discontinuity,不連續/切點)=那條分數上的規則線(65 歲), 一跨過去資格就突然改變。做法:在 65 歲下方配一條回歸線、上方再配一條,看這兩條線在切點處 會不會斷開、跳一下。那個垂直落差(不連續)就是效果。所以「斷點回歸」=在斷點兩側各做回歸、量斷點處的跳幅。

先用白話想一遍

想像大家按年齡排成一排。64.9 歲和 65.1 歲的人幾乎一模一樣,習慣一樣、 健康意識也一樣(就是之前騙過我們的那個看不見的干擾因子)。在 65 歲唯一突然改變的, 只有計畫資格。所以如果健康結果剛好在 65 歲跳一下,那一跳一定來自計畫, 而不是干擾因子,因為干擾因子不會在某個生日突然跳。

銳利 RDD = 結果的「跳幅」

在 65 歲下方與上方各配一條線;兩條線在斷點的落差就是銳利 RD。 它衡量的是「有沒有資格」的效果(類似 ITT),不管人實際有沒有去接種。
估計目標:斷點處所有人的效果(一個落在斷點 65 歲附近的局部平均處置效果 LATE)。

模糊 RDD = 除以「接種率跳幅」

不是每個有資格的人都真的去打。接種率在 65 歲只跳了一部分。 模糊 RD =(結果跳幅)÷(接種率跳幅),代表那些「因為跨過線才去打」的人 (斷點附近的順從者 complier)身上的效果。這其實就是把 IV 用在門檻上。
估計目標:斷點處順從者的 LATE(不是斷點處所有人),正是「把門檻當工具」得到的順從者局部效果。

用試驗的語言看 Sharp 與 Fuzzy:ITT/PP/IV

一場隨機試驗會給你三種對比,RDD 在斷點處正好對得上。 (1) ITT(意向治療,intention-to-treat)=按規則比:有資格 vs 沒資格,不管實際有沒有去打,這就是 Sharp RD。 (2) PP(依方案,per-protocol)=按實際接受治療比:打了 vs 沒打;但「誰會去打」是自我選擇的(比較積極、比較健康的人才跨過去),所以 PP 被混淆、會偏,它不是乾淨的 RDD 答案。 (3) IV 用「有沒有資格」當工具把治療效果救回來:Fuzzy RD =(結果跳幅)÷(接種率跳幅)=順從者 LATE。 所以 Fuzzy RDD 正是 PP 出問題時的 IV 解法,它不是直接比「打了的人」,而是把 ITT 的跳幅,除以「治療實際被推動了多少」。

「視窗」要多寬?兩種講法:連續性 vs 局部隨機化

RDD 只看斷點附近的人,但「附近」要畫多大?這個範圍就叫視窗(頻寬,bandwidth)。 窗開太窄,人太少、估計很跳;開太寬,會把離 65 歲很遠、其實不太像的人也算進來,帶進偏誤。 所以同一份資料,換個頻寬可能得到不同答案,好的 RDD 不該只靠某一個頻寬(這正是 ④ 假設檢驗的 R5)。

為什麼斷點附近就可信?學界有兩種講法:

  • 連續性(continuity):假設「如果沒有門檻,結果會隨年齡平滑變化、不會剛好在 65 歲跳一下」。 於是 65 歲的跳幅就只能來自資格。這是最常見的講法,搭配局部線性與頻寬(對應 ④ 的 R1)。
  • 局部隨機化(local randomization):把斷點附近一個很窄的窗,當成「像隨機分組的小實驗」, 窗內誰落在資格邊內、邊外,近似隨機。⑤ 用 AI 強化 的「藥方一」正是用這個想法,讓估計對頻寬更穩。
看專有名詞解釋

運行變數與斷點 running variable & cutoff

很多真實世界的規則,都是在「某個數字畫的一條硬線」上突然啟動:滿 65 歲就有免費計畫、考試分數過某條線就有獎學金、風險指標超過某值就給加強照護。你被拿來衡量的那個數字,就叫運行變數,同一個東西在不同論文有好幾個名字:running variable(運行變數)、forcing variable(驅動變數)、assignment variable(指派變數),或乾脆叫 score(分數),這四個講的都是這同一個數字,那條線本身就是斷點 c。它之所以好用:一個 64 歲 11 個月的人,和一個 65 歲 1 個月的人,基本上是同一種人,一樣的健康、一樣的習慣、一樣看不見的運氣,但一個剛好有資格、一個剛好沒有。所以若結果正好在這條線上突然跳一階,這一階不可能是「兩群是不同的人」,因為他們根本一樣;只能是那個計畫造成的。唯一需要相信的事叫連續性:如果沒有這條規則,結果會平順地滑過 65 歲、不會自己在那裡跳(Hahn, Todd & van der Klaauw 2001)。你可以這樣檢查:看其他背景特徵在線上有沒有跳、以及線的「幸運那一側」有沒有可疑地擠了一堆人(McCrary 密度檢查)。

銳利 RD sharp RD

「銳利」講的是那個乾淨情況:過線就強制受處置,斷點以上的人全部有、以下全部沒有,沒有例外。當情況這麼整齊時,因果效果就只是結果在線上那一階垂直跳幅的大小。你在斷點下方的人之中畫出趨勢線、上方的人之中再畫一條,把兩條都延伸到線上交會,量出它們之間的落差。那個落差就是答案,因為這兩條平滑趨勢已經把「結果本來就隨年齡漂移」這種一般型態吸收掉了,只剩政策能造出一個突然的階梯。舉例:若健康分數隨年齡平順爬升、卻正好在 65 歲跳升 0.8,銳利 RD 就是 0.8。寫成符號就是兩側單邊極限的差 τ_SRD = lim_{x↓c} E[Y|x] − lim_{x↑c} E[Y|x]。一個提醒:這是線上那一群人的效果(也就是「有沒有資格」的效果,類似 ITT),所以它講的是 65 歲的人,不保證能套到 50 歲或 80 歲身上。

模糊 RD fuzzy RD

現實通常比銳利更亂:過線並不強制受處置,只是讓它更可能發生。65 歲時更多人去打免費疫苗,但不是人人都打,而 65 歲以下也有少數人打。這時結果在線上的跳幅,混了兩件事,真正的處置效果,被「線只把接種率推動了一部分」這件事稀釋掉了。修法就是一個除法:把結果的跳幅,除以接種率的跳幅,這樣就能把「過線的效果」重新放大回「真的有受處置的效果」。舉例:若結果在斷點跳 0.8、接種率跳 0.44,模糊 RD 大約就是 0.8 ÷ 0.44 ≈ 1.8。這其實就是把 IV 的想法用在門檻上,那條線是處置的工具,τ_FRD =(結果的跳幅)÷(接種率的跳幅),它給的是斷點處順從者的效果:那些因為跨過線才去接受處置的人,而不是 65 歲的每一個人(Hahn, Todd & van der Klaauw 2001)。

局部線性迴歸與頻寬 local-linear regression & bandwidth

整個 RDD 的論證其實只在線的正上方才成立,所以你不會用一條曲線去配所有人,你會放大斷點附近的人,並在兩側各配一條簡單的直線。頻寬就只是你對「附近」的定義:65 歲左右各放進幾年進畫面。挑這個數字,正是 RDD 最核心的拉鋸,一個偏差—變異的取捨。窗開窄,你比的是幾乎一模一樣的人(偏差小),但人數很少,答案就晃、信賴區間就寬。窗開寬,人變多(區間變緊),卻開始把 50 歲、80 歲這些真的不一樣的人也拉進來,於是趨勢自然的彎曲又以偏差的形式溜回來。② 的拉桿讓你即時感受:h=6 年會用 59–71 歲,而 h=2 只用 63–67 歲。實作上,你只用窗內的人、在兩側各配一條 Y = α + β(x − c),並給較近的點較高權重;兩條配出來的線在斷點上的落差,就是效果。有資料驅動的規則會自動挑一個平衡這個取捨的窗(Imbens & Kalyanaraman 2012),而穩健偏誤校正的區間,會把信賴帶加寬,補上有限的窗所留下的那點殘餘彎曲(Calonico, Cattaneo & Titiunik 2014)。

RDD 和 IV ①–⑥ 有什麼不同?

兩者都估出「順從者的 LATE」,但「近似隨機」的來源不同。IV 需要一個 真正隨機的工具(提醒)。RDD 則靠斷點上的明確規則:剛好落在線兩側的人可比, 所以不需要任何隨機工具就能處理同一個看不見的干擾因子。代價是:RDD 只能談 斷點附近的人(這裡是 65 歲附近),而且結論會受視窗(頻寬)選擇影響。 最後的 「怎麼選」 分頁有詳細的並排比較。

互動式 RDD:拉動視窗,看「跳一下」怎麼變

拉動下面的頻寬滑桿,改變有多少 65 歲附近的人進入局部線性配適, 即時看「接種率跳幅」「銳利 RD」「模糊 RD」怎麼變。滑桿就在圖的正下方,旁邊兩個讀數讓你一邊拉、一邊看見「偏差—變異」取捨。

接種率在 65 歲的跳幅
–
模糊版的第一階段
銳利 RD(資格效果,類 ITT)
–
模糊 RD(斷點順從者)
–
真正答案藏在 1.80

點是各年齡層「健康分數變化」的分組平均;兩條線是斷點兩側的局部線性配適; 垂直虛線是 65 歲斷點。線上的垂直落差就是銳利 RD。淺色帶就是目前的視窗(±h);拉窄時帶會縮、配適線也只畫在帶內。

視窗內人數(±h) –
95% 信賴區間寬度 · 模糊 RD(變異) –

偏差—變異的取捨:視窗窄→納入的人少→信賴區間變寬(變異變大);視窗寬→人多,但混入較不相似的年齡→估計可能偏離真值 1.80(偏差變大)。拖動滑桿,看著上面兩個數字一起變。

資料分析:跑一次完整的 RDD

載入內建的 65 歲範例,或上傳你自己的 CSV,對應好欄位,跑一次完整的局部線性 RDD, 銳利、模糊、接種率跳幅與配適圖。若你同時對應「事件時間」與「事件指標」, 也會一併跑帶設限的 IPCW/雙重穩健存活型 RDD。

或 尚未載入資料

當結果是「多久後才發生」(存活型):AFT + IPCW + 雙重穩健

資料長什麼樣子?每條線是一個人的追蹤過程

這次的結果不再是一個數字,而是「多久之後會發生大事件」。每條線=一個人,從進場到追蹤結束。 ●=期間真的發生了事件;|=追蹤結束時還沒發生,這個人被「設限」了 (他的資料不完整),它後面那段淡色虛線=事件本來會發生的時間。 體質較弱/較病重的人,往往更早離開,這正是麻煩的地方。

面對這種資料,有兩個方向(剛好相反):

① 增加維度:用 AFT 時間模型

不要只比平均,而是配一個參數化的時間模型,加速失效時間(Accelerated Failure Time, AFT; 例如對數常態、對數羅吉斯),它描述「整段事件時間的分布」,能直接講「處置讓事件時間延後幾倍」, 比單一平均資訊更豐富。這是把同一份存活(time-to-event)分析,從「一個平均效果」增加到整段時間分布的維度。

② 處理設限:IPCW + AFT 合成的雙重穩健(DR)

IPCW(反設限機率加權):在每個觀察到事件的時點,把這個事件乘上 1 ÷(這個人能撐到此刻、還沒被設限的機率),於是每個被看到的事件,也「代表」了那些 特徵相近、卻在自己事件被看到之前就先被設限的人,把因設限流失的資訊補回來。 AFT 則負責描述整段事件時間的分布(見左圖)。把兩者合起來=雙重穩健(DR): 只要「設限模型(IPCW)」或「結果模型(AFT/Cox)」其中一個是對的,估計就不偏。

為什麼用 AFT(而不是風險比 HR)當乾淨的因果目標:可塌縮性(collapsibility)

這裡選 AFT,還有一個細微但重要的理由。Cox 的風險比(HR)是不可塌縮(non-collapsible)的:就算完全沒有混淆, 全體(邊際)HR 也不等於個體 HR 的平均,而且這個數字會因為你多放或少放共變項而改變,所以「校正後的 HR 變了」 可能只是尺度的假象,不一定代表混淆被修掉。HR 還內建了一種隨時間的選擇(體質弱的人先失敗),讓它在因果上不好解讀。 而 AFT 的加速因子(時間比:「處置讓事件時間延後 ×N 倍」)是可塌縮的:邊際效果就是條件效果的合理平均, 而且校正一個不是干擾因子的變項,目標不會跑掉。這正是 Crowther、Royston & Clements(2023)證明 「彈性樣條 AFT 可塌縮、適合因果推論」的原因,把它和上面的設限校正(IPCW/DR)配起來, 就能得到一個可以乾淨解讀的 RDD 存活效果。

實際要跑:在上方欄位對應「事件時間」與「事件指標」、按執行分析,輸出就會出現帶設限的 IPCW/雙重穩健存活型 RD。 分頁 ⑤ 再把結果模型換成彈性 ML(雙重穩健),給出更窄、更穩的估計。


程式(SAS · R · Stata):模糊斷點回歸

出處 — R 與 Stata 皆呼叫 rdrobust 套件的核心函式 rdrobust(),寫法同 rdrobust 官方套件手冊/R Journal 說明文中模糊 RD 的示範(c 指定斷點、fuzzy 指定接受率變數,預設偏誤校正穩健推論)。

這是可直接在可下載的 rdd_sample.csv 上完整執行的程式(欄位:age、eligible、vaccinated、health_score_change、event_time、event、female、bmi、chronic_conditions、income_band)。

SAS — 局部線性回歸

/* read CSV */
proc import datafile="rdd_sample.csv" out=d dbms=csv replace;
    getnames=yes;
run;
/* center age at cutoff 65, keep a bandwidth window, interact with side */
data w;
    set d;
    ac = age - 65;
    right = (age >= 65);
    if abs(ac) <= 10;
run;
/* local linear fit on each side of the cutoff */
proc reg data=w;
    model health_score_change = ac right ac*right;
run;

在 65 歲附近取 ±10 年的頻寬窗口,配合分側指標與交互項,近似局部線性 RD;right 係數即為不連續跳躍。

R — rdrobust 模糊 RD

# fuzzy RD at the age-65 cutoff
library(rdrobust)
d <- read.csv("rdd_sample.csv")
fit <- rdrobust(y = d$health_score_change, x = d$age, c = 65, fuzzy = d$vaccinated)
summary(fit)
# visualize the discontinuity
rdplot(y = d$health_score_change, x = d$age, c = 65)

fuzzy=d$vaccinated 將銳利設計轉為模糊設計:結果的跳躍會除以 65 歲時治療接受率的跳躍。

Stata — rdrobust

* read CSV and fit fuzzy RD
import delimited "rdd_sample.csv", clear case(preserve)
rdrobust health_score_change age, c(65) fuzzy(vaccinated)
* plot
rdplot health_score_change age, c(65)

Stata 的 rdrobust 與 R 呼叫相同:c(65) 為斷點,fuzzy(vaccinated) 為接受率跳躍,並提供偏誤校正的穩健推論。

這個 RDD 可不可信?五道體檢(和 IV 的不一樣)

RDD 依賴的假設和 IV 不一樣。最關鍵的那一條,斷點下方與上方的人很像, 沒辦法用資料直接證明,所以改跑可以檢驗的佐證項目: 運行變數沒有被操弄、背景條件平衡、(模糊版)真的有第一階段跳躍、以及結論在不同視窗下穩不穩。 綠燈沒問題、黃燈要留意、紅燈有狀況。

載入中…

AI 怎麼幫「斷點回歸」一把

因果機器學習一次看懂:從平均效果(ATE)到個體化效果(CATE)

超越單一平均效果。傳統方法估的是一個平均處置效果(ATE)。因果機器學習更進一步,瞄準個體化/條件效果(CATE):誰受益、受益多少。Meta-learners(S-/T-/X-/DR-learner)是與模型無關(model-agnostic)的套法,把彈性 ML 放進輔助模型(結果與傾向模型),而因果識別仍靠和本頁相同的假設,無未測混淆、重疊/正性、一致性。對真實世界資料(EHR、登錄)要小心:彈性 ML 能減少模型設定錯誤的偏誤,但救不了未測混淆,而且「預測得準」不等於「因果效果」。本頁 ⑤ 的示範正是這個想法的一個具體案例,用彈性 ML 處理輔助模型,識別仍來自設計。出處:Feuerriegel 等, Nature Medicine 2024;Kaddour 等, arXiv:2206.15475;Li & Chu 主編, Springer 2023。

還記得 RDD 的兩個痛處嗎?② 互動講解裡,估計會隨你挑的視窗(頻寬)而變; ③ 資料分析裡,帶設限的存活結果需要 IPCW/雙重穩健校正。AI/機器學習正好能把這兩個再磨利 (不重講基礎,基礎見 ② 與 ③),下面用同一個「滿 65 歲」的疫苗故事來看。

藥方一:一個「不挑視窗」的估計(DML)

視窗內的直接比較,視窗開越寬就錯越多。讓 AI 用交叉擬合把年齡和背景條件調整掉, 估計就能在任何視窗下都準。

藥方二:用彈性 ML 處理「設限的存活結果」

當結果是「到事件的時間」又有設限,把設限校正再配一個彈性的結果模型。 只要兩個模型其中一個對就準(雙重穩健),答案也更窄、更穩。

安全帶:交叉擬合(一定要繫)

兩帖藥方都讓 AI 去學一些輔助模型。和 IV 分頁同一條鐵則:永遠用別人的資料學、套到沒看過的人身上 (交叉擬合),否則答案看似漂亮其實騙人。它已經內建在藥方一裡。

藥方一:用雙重機器學習做「不挑視窗」的估計

怎麼做:交叉擬合(離折預測)

資料長什麼樣子?一條有斜率的趨勢、在 65 歲處有一個小跳階

橫軸是年齡、縱軸是結果。兩側都有明顯的隨年齡上升的趨勢,再加上 65 歲(虛線)處一個小跳階, 那個跳階就是我們要的真效果。麻煩在於:結果本來就隨年齡上升,所以若把視窗開寬(琥珀色帶), 只比左側灰點與右側青點的平均,年齡趨勢會把跳階誇大。DML 先把趨勢扣掉,視窗再寬估計也準確。

先用白話想一遍

RDD 比較剛好低於與高於 65 歲的人。正確的做法是用很窄的視窗, 但窄就代表人少、答案會亂跳,於是大家會想把視窗開寬。問題來了: 視窗一寬,兩側的人就不再相像(右邊偏老、左邊偏年輕),直接比較就會偏離真相。 AI 的解法:把年齡與背景條件調整掉(並用交叉擬合,讓它不能作弊), 這樣就算視窗很寬,估計仍然準。拉動下面的視窗,看兩條線:

「DML(雙重機器學習)」到底是什麼?

我們要的其實只有一個數字,因果效果(這裡是真值 1.80)。但要算準它,得先「扣掉」一堆背景干擾(年齡趨勢、其他共變項)。 如果直接拿機器學習去扣,會出現兩個陷阱: (1) ML 為了不過度配適,會刻意把模型縮一點(正則化),這會讓背景預測帶一個小小的、有方向性(系統性)的誤差;而效果是「拿這些背景預測去算」出來的,所以那個系統性誤差會原封不動跟著跑進效果數字裡(不會自己抵消掉)。 (2) 用同一批資料「又訓練模型、又拿來算效果」,等於讓模型偷看它要被打分的答案,數字看似漂亮,換一批新資料就垮。

DML = 雙重/去偏機器學習,用兩招把這兩個陷阱解決掉:

  • 正交化,用一條對「背景模型的小錯不敏感」的算法(雙重穩健/AIPW 分數):就算背景模型估得不夠完美,效果數字也幾乎不動。
  • 交叉擬合,用一折資料訓練背景模型、到另一折沒看過的資料上算效果,模型絕不替自己評分。

「Double(雙重)」有兩層意思:(a) 要配兩個背景模型,結果模型 + 處置(傾向)模型;(b) 只要其中一個對,估計就準(雙重穩健)。 一句話:讓 AI 去擬合複雜的背景,但絕不讓它碰最後那個因果數字,那個數字由正交分數 + 交叉擬合來保護。

視窗內直接比較
–
DML(調整+交叉擬合)
–
真正答案藏在 1.80
直接比較偏了多少
–
相對真值 1.80

琥珀色線是視窗內直接比較:只有在很窄的視窗才靠近 1.80,視窗一寬就一路爬高、偏離真相。 青色線是 DML:在每一個視窗下都緊貼真值 1.80(綠虛線)。同一筆資料,差別只在 AI 有沒有把年齡和背景調整掉。

看專有名詞解釋

視窗內直接比較(局部隨機化) local-randomization difference in means

白話:就在一個小視窗內,把斷點上方與下方的人各取平均,相減。
定義:把斷點附近的窄帶當成「小型隨機實驗」,直接算兩邊的平均差,不調整任何共變項。
為什麼重要:它只有在很窄的視窗才不偏;視窗一放寬、為了多納入人,就會混入較不相似的年齡,估計開始漂掉(就是圖上那條一路爬高的琥珀線)。
例子:64–65 歲與 65–66 歲的健康變化平均相減。
公式:τ = Ȳ(斷點上方) − Ȳ(斷點下方)。

雙重穩健(AIPW)分數 doubly-robust / AIPW score

白話:讓 AI 把年齡與背景調整掉,並用「兩道保險」,就算其中一道有破洞答案也撐得住。
定義:增廣反機率加權(AIPW)分數把傾向模型與結果模型結合;只要其中一個對就一致(雙重穩健)。輔助模型都用離折預測(交叉擬合,見 IV ⑤)。
為什麼重要:它在這裡最突出的特性是對頻寬/視窗選擇穩健,青色線在每個視窗下都緊貼真值,和「直接比較」截然不同。
例子:傾向(誰落在 65 歲以上)+結果(給定年齡背景下的健康),用 AIPW 結合。
公式:τ = E[ μ₁−μ₀ + D(Y−μ₁)/e − (1−D)(Y−μ₀)/(1−e) ]。

DML/95% 信賴區間 recap

DML(雙重/去偏機器學習)與 95% 信賴區間的完整定義見 IV ⑤「看專有名詞解釋」。這裡的重點:有了 AI 調整+交叉擬合,RDD 估計不管視窗怎麼選都貼近真值,這個「對頻寬穩健」就是它的價值所在。

藥方二:用彈性 ML 處理帶設限的存活結果

怎麼做:雙重穩健的搭配(兩道保險)

資料長什麼樣子?每個人是一條可能被中途切斷的時間線

每一條橫線是一個人,從左往右被追蹤。紅點=事件發生了(我們看得到真正的時間); 空心刻度=追蹤先結束,我們只知道「還沒發生」(設限);它後面那段淡色虛線= 事件本來會發生的時間,只是我們沒觀測到。麻煩在於:體質較弱/較病重的人,往往更早被設限, 所以設限不是隨機的,跟你是誰有關。忽略它答案就偏;IPCW 與雙重穩健模型就是 AI 校正它的方法。

這裡的 AI 之處(設限/IPCW/DR 的基礎在 ③)

③ 已經介紹過怎麼用 IPCW + 雙重穩健(Cox/AFT 結果模型)處理帶設限的存活結果。這裡的 AI 之處很單純: 把那個結果模型換成彈性 ML。因為估計是雙重穩健的,只要其中一塊對就準,而當結果曲面非線性時, 彈性模型會給出更窄、更穩的答案。按下面跑跑看(要擬合模型,約需幾秒):

看專有名詞解釋

設限 censoring

白話:追蹤在事件發生前就結束了,我們只知道「還沒發生」,真正的事件時間沒看到。
定義:當研究(或某人的追蹤)在仍未發生事件時停止,該觀測即為右設限;只知道事件時間超過最後觀測時點。
為什麼重要:若誰被設限跟他是誰有關(體弱者更早離開),忽略它就會偏,這裡的設限是有訊息的,不是隨機的。
例子:較病重的人第 3 年退出,我們永遠看不到他的事件會不會、何時發生(圖中那段淡色虛線)。
符號:觀測到 T̃ = min(T, C) 與指標 δ = 1{T ≤ C}。

IPCW(反設限機率加權) inverse-probability-of-censoring weighting

白話:在每個「看到的事件」上加重,讓它也替「特徵相近、卻在自己事件被看到前就先被設限」的人發聲。
定義:把每個觀察到的事件,乘上 1 ÷(這個人能撐到此刻、仍未被設限的估計機率),在共變項相近的人之間進行。
為什麼重要:它把「有訊息的設限」戳出的破洞補回來,但完全依賴設限模型正確,所以可能不穩。
例子:若相近的人只有 60% 仍未被設限,每個觀察到的事件就約算 1/0.6 ≈ 1.7 倍。
公式:權重 wᵢ = δᵢ / Ĝ(T̃ᵢ | Xᵢ),Ĝ 為仍未被設限的機率。

加速失效時間模型(AFT) accelerated failure time

白話:一個說「處置把整段事件時間按固定倍數拉長」的模型,事件晚(或早)×k 發生。
定義:把 log(事件時間)對共變項做迴歸的參數存活模型;係數是時間加速因子(如對數常態、對數羅吉斯)。
為什麼重要:它描述整段時間分布(不只一個平均),可直接在斷點處套用(Adeleke 等人 2022);分布假設成立時有效率,但設定一錯就脆弱。
例子:×1.7 倍=處置下事件晚 70% 發生。
公式:log T = Xβ + σε;加速因子=exp(β)。

雙重穩健(DR) doubly robust

白話:把設限模型(IPCW)和結果模型(Cox/AFT)配成一對,只要其中一個對,估計就對;兩道網,一道夠用。
定義:結合「反機率(設限)模型」與「結果迴歸模型」的估計式;至少一個設定正確就一致,且比單一工作模型更有效率、更穩健。
為什麼重要:它消掉純 IPCW「單點失效」的弱點,給出更窄、更穩的估計,圖中兩個 DR 版本落點接近、誤差範圍最窄。
例子:IPCW(設限)+ AFT(結果)結合;就算設限模型略偏,好的 AFT 也能救回來。
關鍵特性:設限模型「或」結果模型其一正確即一致。

前沿閱讀:彈性 ML/雙重穩健的 RDD

上面「用 AI 強化 RDD」的想法,最近有兩條研究把它推得更遠。兩者都沿用同一套 RDD 識別(斷點處的連續性/局部隨機化),只是改變了「估計怎麼向共變項與 ML 借力」。

① RDFlex:用彈性共變項調整換精度(Noack, Olma & Rothe 2024)

標準 RDD 把共變項丟掉(或只線性放入)。RDFlex 用雙重/去偏 ML 先把結果對基線共變項做彈性殘差化,再對「調整後的結果」跑局部線性 RDD。斷點跳幅期望值不變(共變項在斷點處連續、製造不出跳幅),但殘差變小、噪音變低,信賴區間更窄,等於平白多出精度,並用交叉擬合防過度配適。它sharp 與 fuzzy 都適用,已實作於 DoubleML 套件(RDFlex)。它是藥方一「對頻寬穩健 DML」的精度版表親。

② DR-RDD:雙重穩健、收斂更快的 RD 估計(Kato 2024)

局部線性 RDD 是無母數的,收斂率比 √n 慢、推論也較棘手。Kato 的 DR-RDD 把兩個條件結果的估計式用去偏(雙重穩健)校正結合:其一對就一致;而當兩個都只是還可以時,能達到 √n 一致性(比一般無母數率快),也讓推論更簡單。同一套 RD 識別、更好駕馭的估計式。(與藥方一 AIPW 分數同樣的雙重穩健精神,這裡瞄準的是收斂率。)

這兩者屬進階閱讀,本頁未做成互動示範。重點:AI 在兩個軸上幫 RDD,對視窗穩健(藥方一/DR-RDD)與從共變項換精度(RDFlex),而不改變「RDD 為何成立」的根本。

第三種招式:比較兩組各自的「前→後變化」(DiD)

同一個疫苗故事,再換一種設計。假設某縣市衛生局在某個時間點,對部分社區開啟一個 「疫苗快打車+到府提醒」的政策,其他社區則沒有。我們每一期量一次各社區的平均健康分數。 差異中的差異(DiD)就是比較「介入組的前→後變化」與「對照組的前→後變化」, 來讀出政策的效果。

先用白話想一遍

兩個社區永遠不會一模一樣,其中一個可能本來就比較健康(一個固定落差)。而且每個社區都會隨時間漂移 (一個共同趨勢,景氣好、整體變好)。如果只比介入社區的前 vs 後,會被共同趨勢汙染; 只比後期的介入 vs 對照,會被固定落差汙染。DiD 把兩者都消掉:拿介入組的變化(後−前), 再減掉對照組的變化(後−前)。固定落差消掉(它同時在前期與後期);共同趨勢也消掉(它同時打到兩組)。 剩下的,就是政策效果。

把名字拆開來看:到底是哪兩個「差異」?

名字是「差異中的差異」,先有兩個差異,再把這兩個差異相減一次:

  • 差異①=介入組自己的「後 − 前」變化(一個前後差異)。
  • 差異②=對照組自己的「後 − 前」變化(另一個前後差異)。
  • 差異中的差異=差異① − 差異②。一相減,就把「共同的時代趨勢」(兩組都有)和「組間固定落差」一起消掉,剩政策效果。

資料長什麼樣子?兩條原本平行的線,直到政策上路

每條線是一組隨時間的平均結果。政策上路前(虛線左側),兩條線平行上升,斜率相同、只差一個固定落差。 在斷點處,政策對青色(介入)組開啟,它的線就跳到原本平行路徑的上方。多出來的那一段, 青色線減掉它自己那條虛線「假如沒政策會怎樣」的延伸,就是 DiD 效果。

2×2 食譜

最簡單只需要四個平均:介入-前、介入-後、對照-前、對照-後。 DiD =(介入-後 − 介入-前)−(對照-後 − 對照-前)。這一個減法就是全部精髓。

它估的是什麼(估計目標)

DiD 給的是政策後介入組的平均處置效果(ATT),前提是沒有政策時兩組會平行移動。 它是「組別×時間」的平均,不是某一個人的效果。

看專有名詞解釋

差異中的差異(DiD/ATT) difference-in-differences / ATT

假設某政策在一部分城鎮啟動、另一部分沒有,而你想知道它的效果。只在事後比「處置鎮 vs 對照鎮」並不公平,它們本來就不一樣;只比一個處置鎮的前後也不公平,反正所有東西都會隨時間漂移。DiD 用兩次相減同時躲開這兩個陷阱:取處置組的「前→後變化」,再減掉對照組的「前→後變化」。第一個相減把城鎮之間「永遠就不同」的部分抹掉;第二個相減把「對所有人都在發生」的時間變化抹掉。剩下的就是政策效果,寫成 (處置-後 − 處置-前)−(對照-後 − 對照-前)。例子:處置鎮升 5、對照鎮升 2,DiD = 5 − 2 = 3。由於它只把對照組當成處置組的替身,所以它估的是處置組身上的平均效果(ATT),不是所有人的效果(Card & Krueger 1994)。一個提醒:當各鎮在不同時間採用政策、且效果不一致時,這個簡單相減可能誤導,因而有更新的估計器(Callaway & Sant'Anna;Goodman-Bacon)。

平行趨勢 parallel trends

DiD 的整個動作,「把對照組的變化減掉」,只在「對照組的變化能確實代表處置組『若沒政策會怎樣』」時才公平。平行趨勢正是這個承諾:若政策從未到來,兩組的平均本會同步往上(或往下)漂、維持彼此一樣的差距。它們不必從同一水準出發,只要並肩移動就好。若處置組在政策前就已經在領先拉開,DiD 會把這個較早的「先跑」誤當成政策效果。例子:若政策前幾年兩組都約每年升 2,平行趨勢就可信;若處置組事前就在加速,就不可信。麻煩在於你永遠無法直接檢查後期,你看不到處置組在事後沒受政策的樣子。但前期是一個強力檢定:若政策前的事件研究點是平的(見 ④),平行趨勢看來就安全;而敏感度分析(Rambachan & Roth 2023)會告訴你結論還能承受多少隱藏的漂移。

事件研究 event study

事件研究不把一切壓成一個「前 vs 後」的數字,而是以「政策前一刻」為基準,替每一期各估一個效果,再畫成一條穿越時間的線。一張圖做兩件事。政策之前的那些期是一個檢查:若兩組真的並肩移動,這些點就該平貼在 0 附近,所以政策前只要有漂移,就是「平行趨勢失敗」的明顯警訊。政策之後的那些期則顯示效果的形狀,是立刻發生、慢慢累積、還是逐漸消退。例子:第 −3、−2、−1 年的點約為 0(好,事前是平的),第 0、1、2 年為 1、3、4(效果在成長)。技術上你配 Y = Σ_k δ_k·1{期別 = k} + 單位與時間固定效果,丟掉一個基期(通常是政策前一刻 k = −1),讓其他每期都相對它來讀;前期的 δ 檢定平行趨勢,後期的 δ 描出效果隨時間的軌跡。當各鎮開始時間不一致時,要特別小心別讓「已受政策的鎮」悄悄汙染比較(Sun & Abraham 2021)。

群集穩健標準誤 cluster-robust standard error

觀察同樣 40 個城鎮、長達 10 年,你有 400 列,但不是 400 份獨立的事實。一個城鎮今年高、明年往往也高,它的各列會像一團一起動。若你假裝這 400 列彼此獨立,數學就以為你的證據遠比實際多,信賴區間算得太窄,搖晃的結果看起來卻「顯著」。群集穩健標準誤的修法是:把每個城鎮(而不是每個城鎮-年)當成真正的資訊單位,允許它的重複各列以任何方式相關。例子:40 個城鎮 × 10 年,就以城鎮群集(40 群),而不是以 400 個城鎮-年。Bertrand, Duflo & Mullainathan(2004)指出 DiD 忽略這種相關會嚴重誇大顯著性。一個限制:這個修法仰賴城鎮數夠多;若群集只有少少幾個(低於約 30–40),它會過度修正,需要 wild-cluster bootstrap 之類的額外技巧(Cameron & Miller 2015)。

DiD 和 IV、RDD 有什麼不同?

IV 從隨機工具借隨機;RDD 從分數上的明確門檻借;DiD 則從時間借,一個在已知時間點 對部分組別開啟、其他組別沒有的政策。它的關鍵假設是平行趨勢:沒有政策時,介入與對照會以相同步調變化。 和前兩者一樣,這條核心假設無法完全證明,但政策前的期數能提供有力的檢查(分頁 ④)。

互動式 DiD:打破平行趨勢,看估計怎麼歪掉

DiD 成敗全看平行趨勢。拉動滑桿,讓介入組在政策還沒上路前就偷偷往上漂。 看三件事一起變:前期兩條趨勢線拉開、事件研究的點在斷點前就離開 0、DiD 估計偏離真值 3.0。

DiD 估計
–
真正答案是 3.00
未校正:只看後期差(有偏)
–
被各組固定落差汙染
前期趨勢檢查
–

兩條隨時間的組平均線;垂直虛線是政策上路的時點。滑桿在 0 時,政策前的兩段是平行的; 往上推,青色(介入)線就提早翹起來,這個提早分岔正是讓 DiD 出錯的元兇。

事件研究:每個點是某一期「介入減對照」的落差,以政策前最後一期為基準(設為 0)。 政策前的點貼近 0 就支持平行趨勢;若它們在斷點前就離開 0,假設正在崩壞。

資料分析:跑一次完整的 DiD

載入內建的政策範例,或上傳你自己的面板 CSV(每列=一個單位×一期),對應好欄位, 跑一次完整的 DiD,2×2 估計、群集穩健迴歸、兩條趨勢線與事件研究前期檢查。

或 尚未載入資料

程式(SAS · R · Stata):差異中的差異(雙向固定效果)

出處 — R 使用 fixest 套件的 feols(),寫法同 fixest 官方 walkthrough vignette 的雙向固定效果示範(| 之後列固定效果 unit + period,cluster = ~unit 做群集標準誤);Stata 為官方手冊的 xtset + xtreg, fe cluster()。分階段採用(staggered adoption)建議改用 did 套件(Callaway 與 Sant'Anna)。

這是可直接在可下載的 did_sample.csv 上完整執行的程式(欄位:unit、period、treated、post、health_score、urban、baseline_burden)。

SAS — proc glm 搭配 absorb

/* read CSV */
proc import datafile="did_sample.csv" out=d dbms=csv replace;
    getnames=yes;
run;
/* TWFE: absorb unit FE, period as class, treated*post is the DiD term */
proc glm data=d;
    absorb unit;
    class period;
    model health_score = treated*post urban baseline_burden period / solution;
run;

absorb unit 消去單位固定效果;class period 加入期別效果;treated*post 交互項即為差異中的差異估計值。

R — fixest::feols

# two-way fixed-effects DiD, SE clustered by unit
library(fixest)
d <- read.csv("did_sample.csv")
fit <- feols(health_score ~ treated:post + urban + baseline_burden | unit + period,
            data = d, cluster = ~unit)
summary(fit)
# for staggered adoption, see the did package (Callaway & Sant'Anna)

直線 | 之後的固定效果(unit + period)吸收兩個維度;treated:post 為 DiD 係數,標準誤依 unit 群集。

Stata — xtreg fe

* read CSV and set panel
import delimited "did_sample.csv", clear case(preserve)
xtset unit period
* TWFE with clustered SE; reghdfe or didregress are alternatives
xtreg health_score i.treated#i.post urban baseline_burden i.period, fe cluster(unit)

xtset 宣告面板;i.treated#i.post 交互項為 DiD 項,含單位固定效果與期別虛擬變數。reghdfe 與 didregress 為便利的替代方案。

這個 DiD 可不可信?五道體檢

DiD 依賴平行趨勢:沒有政策時,兩組會一起變。這在政策後本質上無法證明,所以改跑可以檢驗的項目:前期趨勢(事件研究)檢查、無預期、足夠前期與完整面板、無外溢、 以及足夠的群集數讓推論可信。綠燈沒問題、黃燈要留意、紅燈有狀況。

載入中…

DiD 真正用到機器學習的那一個地方

因果機器學習一次看懂:從平均效果(ATE)到個體化效果(CATE)

超越單一平均效果。傳統方法估的是一個平均處置效果(ATE)。因果機器學習更進一步,瞄準個體化/條件效果(CATE):誰受益、受益多少。Meta-learners(S-/T-/X-/DR-learner)是與模型無關(model-agnostic)的套法,把彈性 ML 放進輔助模型(結果與傾向模型),而因果識別仍靠和本頁相同的假設,無未測混淆、重疊/正性、一致性。對真實世界資料(EHR、登錄)要小心:彈性 ML 能減少模型設定錯誤的偏誤,但救不了未測混淆,而且「預測得準」不等於「因果效果」。本頁 ⑤ 的示範正是這個想法的一個具體案例,用彈性 ML 處理輔助模型,識別仍來自設計。出處:Feuerriegel 等, Nature Medicine 2024;Kaddour 等, arXiv:2206.15475;Li & Chu 主編, Springer 2023。

雙重/去偏機器學習 DiD(DML):當「誰受處置」與時間趨勢都非線性地取決於許多共變項時, 用梯度提升去估那些輔助模型、再用交叉擬合去偏。下面會真的在你的瀏覽器裡跑 scikit-learn (scikit-learn 是 Python 最常用的開源機器學習套件)。

為什麼這裡要 ML、又為什麼叫「雙重」

雙重穩健 DiD 同時配一個傾向分數模型(誰比較會受處置)與一個結果模型(對照組的自然變化), 只要其一對就不偏。用線性模型配非線性真相會留下偏誤;改用梯度提升+交叉擬合 (用別折學、套到沒看過的折),估計就回到真值。這就是 DML,「雙重」=兩個輔助模型、再去偏。

AI 藥方:雙重/去偏機器學習(DML)

怎麼做 ①:雙重穩健分數(兩道保險)

怎麼做 ②:交叉擬合(讓 ML 不能替自己評分)

第四種招式:搭上一個新疫苗逐漸普及的浪潮(趨勢中的趨勢)

假設一個新疫苗在好幾年間逐漸普及。某些人比其他人更早、更快開始用它。趨勢中的趨勢問: 如果這支疫苗真的會引發某個(罕見)不良事件,那麼事件率上升得最快的,應該正好是接種率上升得最快的那群人。 這「兩個趨勢一起動」,接種率與結果率,就是訊號。

先用白話想一遍

會去接種新疫苗的人,通常和沒接種的人本來就不一樣,常常是本來就風險較高(所以才被優先接種)。 於是直接比較「接種 vs 不接種」,會讓疫苗看起來比實際更有害,這是典型的適應症混淆。 趨勢中的趨勢繞過它:它不是比較人,而是比較時間趨勢。先用基線特徵幫每個人打一個 「會不會去接種」的分數(CPE),照分數分層。疫苗會在高分層普及得比較快。如果結果率也在那裡 爬得比較快、和接種率同步,這種同步很難用「固定不變的背景差異」假裝出來,因為那些差異不會突然開始有趨勢。

把名字拆開來看:到底是哪兩個「趨勢」?

名字是「趨勢中的趨勢」,它看的是「一個趨勢會不會跟著另一個趨勢走」:

  • 趨勢①:暴露的趨勢。接種率隨日曆時間上升,而且在某些族群(CPE 層)漲得比別層快。
  • 趨勢②:結果的趨勢。不良事件率在每一層也隨時間變化。
  • 趨勢中的趨勢問:結果的趨勢會不會跟著暴露的趨勢走?如果在接種率漲得快的層、事件率也漲得快,這兩個趨勢的「同步」就是因果訊號,而且固定的混淆很難假裝,因為固定的東西不會突然開始有趨勢。

把兩個趨勢並排看:結果趨勢有沒有跟著暴露趨勢走?

趨勢中的趨勢是從「暴露趨勢裡的結果趨勢」讀出因果效果。左圖:每條線是一個 CPE 層的接種率(暴露)隨日曆時間的變化,它們扇形散開,高傾向層(青色)陡升、低傾向層(灰色)幾乎不動。右圖:同樣這些層的事件率(結果)。若暴露真的造成結果,右邊的扇形會跟左邊一模一樣,接種上升最快的層,正是事件率上升最快的層。這個同步就是訊號;一支平平、沒有趨勢的暴露,這個方法就無從下手。

① 暴露趨勢(接種率)

② 結果趨勢(事件率):跟著暴露的扇形走

它估的是什麼

暴露對結果的因果勝算比(因結果罕見,≈相對風險),從格子層級的趨勢還原,而不是被混淆的個體層比較。

為什麼可能勝過世代研究

會讓趨勢中的趨勢出錯的情境(一個未測因素也隨時間變化、剛好和接種潮同步)是會讓世代研究出錯情境的 子集。所以它更穩,代價是需要一個夠強的接種趨勢。

看專有名詞解釋

趨勢中的趨勢(TiT) trend-in-trend

一個新藥在族群裡是慢慢普及的,而且不是每個人都同樣快開始用。趨勢中的趨勢就把這種「快慢不一的普及」當成一場自然實驗。想法很單純:如果這個藥真的會造成某種傷害,那麼在這幾年裡用藥率爬升最快的那群人身上,傷害事件也應該升得最快;在用藥率持平的群裡,事件也該持平。所以它不用那種危險的人頭比較「有用藥 vs 沒用藥」,那種比較會被「病重的人比較會去選這個藥」汙染,而是看事件率的上升有沒有跟著用藥率的上升同步走,既看時間、也看不同群(這就是「趨勢裡面又有一個趨勢」)。舉個例:在用藥率從 5% → 40% 的那群,事件率也升得很陡;在用藥率不動的那群,兩者都不動,這種同步指向真有效果,而且固定不變的背景差異很難假裝出來,因為固定的東西不會突然開始有趨勢。寫成式子(Ji, Small, Leonard & Hennessy 2017),它就是去配「事件盛行率怎麼隨各群的用藥盛行率與時間變化」,再讀出因果勝算比 OR = exp(β₁)。

累積暴露機率(CPE)與分層 cumulative probability of exposure & strata

要比較「用得快」和「用得慢」的人,方法得先把每個人歸到這些群裡,而且必須在不偷看「誰真的用了藥」的情況下做,否則推理就變成循環了。所以它對每個人只用他一開始的特徵(年齡、健康狀況等),算出一個分數:他最後有多可能用上這個藥,這個分數就是累積暴露機率,簡稱 CPE,再照分數把人分箱,比方說從最不可能到最可能分成五箱。這些箱(叫做「層」)之所以有用,正是因為它們用藥的速度不同:最高層的用藥率一路飆升,最低層幾乎不動,而這種速度的散開就是整個方法運作的原料。實際上 CPE 分數只是用基線特徵跑一個邏輯斯模型給出的預測 CPE = logit⁻¹(X·γ),再切成 K 個一樣大的箱(Ji 等 2017);因為箱是用「固定不變的起始特徵」建的,群與群之間單純的差異會被吸收掉,真正承載答案的是各箱「不同的時間趨勢」。

罕見結果假設 rare-outcome assumption

這個方法講的是「勝算比」的語言,而這套語言只在「壞事件真的少見」時才保持準確。「勝算比」是一種比較兩個機率的方式;當事件罕見時,它幾乎等於比較直覺的「相對風險」(事件變成幾倍可能),讓方法把「事件率怎麼跟著用藥走」翻譯成一個乾淨因果數字的代數才站得住。但當事件常見時,勝算比和相對風險就會拉開,OR 會高估真正的風險上升,那套代數開始走樣,估計可能偏離真相。所以整體發生率 1–2% 的不良事件在這裡沒問題;發生在 30% 人身上的結果就破壞了這個假設,你不該把 OR 當成單純的風險比來讀。好消息是這件事可以檢查、而不只是假設,你可以直接在資料裡看整體事件率(Ji 等 2017),若它接近邊界,就保守看待 OR,或改用不需要「罕見」這個條件的方法。

適應症混淆 confounding by indication

這是幾乎每個藥物安全研究都揮之不去的那個偏誤,也是為什麼未校正的「有用藥 vs 沒用藥」比較常常誤導人。醫師不是隨機發藥:最病重的人,疾病最活躍或最嚴重的那些,既最可能被開這個藥,又因為同樣的嚴重度,本來就(不管有沒有用藥)最可能發生壞結果。所以當用藥那組看起來比較差時,你分不出有多少是藥造成的、有多少只是因為他們本來就病重,兩者糾纏到拆不開。舉例來說,粗略比較可能顯示勝算比約 4,疊在真實效果只有約 2 之上;那個被灌大的差距是適應症滲進來,而不是藥多出來的傷害。用因果圖的話講,潛在的嚴重度同時是「用藥」和「結果」的共同成因(在 用藥 ← 嚴重度 → 結果 這條路徑上的混淆),調整你量得到的嚴重度有幫助,但很少能除掉你量不到的。趨勢中的趨勢繞過它的方式,是從「用藥與結果如何隨時間、跨群一起變動」來讀效果,而不是靠人頭對比,於是任何穩定、不隨時間變化的嚴重度效果都會相消(Ji 等 2017)。

TiT 和 IV、RDD、DiD 有什麼不同?

IV 從隨機工具借隨機;RDD 從明確門檻借;DiD 從某時點開啟的政策借。趨勢中的趨勢則從 暴露盛行率隨時間、且跨層不同的逐漸趨勢借,沒有工具、沒有門檻、沒有單一開關日期, 只有採用率上升的浪潮。它關鍵(不可檢驗)的假設是:沒有未測因素隨日曆時間、跨層地與這股採用潮同步變化。

互動式 TiT:把趨勢調弱,看方法怎麼「沒訊號」

趨勢中的趨勢完全靠暴露趨勢的強度活著。拉動滑桿,讓疫苗普及得更慢。看接種率曲線變平, 也看估計失去著力點,信賴區間大幅變寬、點估計從真值 OR=2.0 飄走。這就是假設 A1(與檢定力)的現場示範。

趨勢中的趨勢 OR
–
真正答案是 2.00
95% 信賴區間寬度
–
未校正世代 OR(有偏)
–
被適應症混淆

各 CPE 層的接種率隨時間變化。滑桿在 1.0 時各層強烈扇形散開;調低後變平,上方的趨勢中的趨勢估計也跟著失準。

同樣各層的結果(不良事件)率。趨勢中的趨勢看它是否以和接種率相同的扇形散開;兩個趨勢越同步,估計越銳利。

資料分析:跑一次完整的趨勢中的趨勢

載入內建的接種普及範例(或上傳一份長格式 CSV,含 pid/period/exposed/outcome 欄位與基線共變項)。 工具會建立 CPE 分層、聚合「期別×層」格子、擬合趨勢中的趨勢概似,並把因果勝算比與未校正世代比較並列。

或 尚未載入資料

加碼:跑已發表的 Ji & Small 估計器(完整 cell-MLE)

上面 ③ 的估計用的是又快又穩的邊際近似。這顆按鈕會跑完整、已發表的 cell-MLE(TrendInTrend::OR,Ji & Small 2017),完整 2×2 概似、每層潛在 CPE 動差、遞迴 h(t),資料是 Ji & Small 生成機制的合成集(10 萬人、20 期),在這個規模下才足以識別擬合。這是貨真價實的發表版估計器,附上它偏寬的重抽樣區間。(離線預算:完整多起點最佳化約需 25 秒、會凍結瀏覽器。)


程式(SAS · R · Stata):趨勢中的趨勢設計

出處 — R 使用 TrendInTrend 套件的主力函式 titanalysis(n11, n10, G1, G0),輸入的各期分層計數格式與呼叫方式同 TrendInTrend 官方套件手冊示範(該套件由 Ji 與 Small 隨方法一併發布)。

這是可直接在可下載的 tit_sample.csv 上完整執行的程式(欄位:pid、period、x1、x2、exposed、outcome)。

SAS — proc nlmixed 概似

/* read CSV */
proc import datafile="tit_sample.csv" out=d dbms=csv replace;
    getnames=yes;
run;
/* exposure-conditional logistic likelihood with a period trend */
proc nlmixed data=d;
    parms b0=0 bt=0 be=0 b1=0 b2=0;
    eta = b0 + bt*period + be*exposed + b1*x1 + b2*x2;
    p = 1/(1+exp(-eta));
    model outcome ~ binary(p);
run;

proc nlmixed 將暴露條件概似最大化,讓期別趨勢(bt)與暴露(be)共同解釋結果。

R — TrendInTrend::titanalysis

# trend-in-trend: exploit the differential exposure trend across periods
library(TrendInTrend)
d <- read.csv("tit_sample.csv")
# build the period x exposure count tables required by the package
G1 <- table(d$period, d$exposed)[, "1"]   # exposed counts
G0 <- table(d$period, d$exposed)[, "0"]   # unexposed counts
n11 <- table(d$period[d$outcome==1], d$exposed[d$outcome==1])[, "1"]
n10 <- table(d$period[d$outcome==1], d$exposed[d$outcome==1])[, "0"]
fit <- titanalysis(n11, n10, G1, G0)
print(fit)

titanalysis() 以各期別中暴露與未暴露者的結果計數作為輸入,從差異化的暴露趨勢中還原出勝算比。

Stata — logistic 趨勢交互

* approximate trend-in-trend via a period-trend interaction
import delimited "tit_sample.csv", clear case(preserve)
logit outcome c.exposed##c.period x1 x2, or

Stata 沒有原生的趨勢中趨勢指令;exposed 與 period 的交互項近似地利用差異化暴露趨勢,以勝算比呈現。

這個 TiT 可不可信?五道體檢

趨勢中的趨勢依賴:暴露趨勢夠強、結果夠罕見、可測特徵不隨時間漂、以及,關鍵且不可檢驗的, 沒有未測因素隨日曆時間、跨層地與接種潮同步變化。綠燈沒問題、黃燈要留意、紅燈有狀況、藍燈需領域判斷。

載入中…

限制,以及本工具和原版估計式的差別

  • 兩種估計器。常駐的 ③ 估計用又快又穩的邊際模型(看結果盛行率跨層怎麼跟著暴露盛行率走,信賴區間用 Hessian),識別想法和發表版相同,但不是同一條概似。完整的發表版 cell-MLE(TrendInTrend::OR(),Ji & Small:完整 2×2 計數、每層潛在 CPE 動差 C1/C2/C3、遞迴 h(t)、多起點 MLE+自助法 CI)也實作了,可從 ③ 分頁的「跑已發表的估計器」按鈕執行。常駐分頁之所以用邊際模型,是因為在瀏覽器可行的樣本量下,β₁(log-OR)識別很弱:概似面在 β₁ 上幾乎是一條平脊,不同起點會落到差很多的解卻有幾乎一樣的概似值(這也是套件本身會回報「多重解/可能不可靠」、需要牛頓步+自助法+可識別性檢查的原因)。所以較重的發表版另外提供:在一個夠識別的 Ji & Small 生成資料上離線預算,並附上它(弱識別下)偏寬的區間。
  • CPE 其實就是傾向分數,而且是用「基線」共變項算的。已發表的設計是用基線特徵建累積暴露機率(本工具也是)。若改用整段研究期間量到的共變項,可能漏進暴露後的資訊,這是個需要慎重的設計選擇,不能隨手換。
  • 它建模的是「每期的盛行率」,所以適合反覆發生/盛行型/急性的結果,而不原生處理帶設限的存活(time-to-event)結果。因為每個(層×期)格子是橫斷面的計數,一個人若死亡(或被設限),在這個框架下仍然留在分母裡。若是一次性、且死亡率有差異的致命事件,這會讓格子率偏掉;要正確處理存活/競爭風險,是這個設計尚待解決的問題。

用 AI 強化 TiT:文獻目前還沒有

因果機器學習一次看懂:從平均效果(ATE)到個體化效果(CATE)

超越單一平均效果。傳統方法估的是一個平均處置效果(ATE)。因果機器學習更進一步,瞄準個體化/條件效果(CATE):誰受益、受益多少。Meta-learners(S-/T-/X-/DR-learner)是與模型無關(model-agnostic)的套法,把彈性 ML 放進輔助模型(結果與傾向模型),而因果識別仍靠和本頁相同的假設,無未測混淆、重疊/正性、一致性。對真實世界資料(EHR、登錄)要小心:彈性 ML 能減少模型設定錯誤的偏誤,但救不了未測混淆,而且「預測得準」不等於「因果效果」。本頁 ⑤ 的示範正是這個想法的一個具體案例,用彈性 ML 處理輔助模型,識別仍來自設計。出處:Feuerriegel 等, Nature Medicine 2024;Kaddour 等, arXiv:2206.15475;Li & Chu 主編, Springer 2023。

在另外三個方法,這個分頁能展示具體、已發表的 ML 升級。對趨勢中的趨勢, 在我們依據的來源論文裡,並沒有成熟的機器學習或雙重穩健版本的趨勢中的趨勢。 所以與其假裝有,不如說明文獻有什麼、沒有什麼,再加上清楚標示為推測的、AI 可能幫得上忙的方向。

來源論文實際上有什麼

趨勢中的趨勢的論文(Ji & Small 2017;Ertefaie 等人的檢定力短文;鴉片類與輔助治療的應用)在聚合的 「期別×層」表上用古典最大概似,搭配傾向分數式的 CPE 分層。在此處所代表的這個方法的已發表文獻中, 沒有機器學習、沒有交叉擬合、沒有雙重穩健估計。這就是目前的現況,不是我們能用一個漂亮的 demo 掩蓋過去的缺口。

有沒有可能的「AI 藥方」?目前不知道,但有可能…

以下是我們謹慎的推測(可能的藥方,不是成熟的藥方),不是任何論文的結果。請當成研究方向,而非建議:

① 更彈性的 CPE 模型(推測)

累積暴露機率(CPE)模型其實就是一個傾向分數。原則上用機器學習估 CPE(梯度提升等)或許能把各層的暴露趨勢拉得更開、提升檢定力,就像 ML 傾向分數在別處的幫助。對趨勢中的趨勢尚未驗證。

② 雙重穩健增廣(推測)

類比 DiD 與 RDD,或許能想像把趨勢中的趨勢概似配上一個彈性結果模型與一條正交(去偏)分數,讓某一塊設定錯了也不會拖垮估計。但就這些論文而言,這個設計是否存在有效的正交分數,仍是未解的問題。

③ 異質性與敏感度(推測)

因果森林或許能探討效果是否隨次群體而異;E-value 式的敏感度分析或許能量化:一個與暴露同步的時代混淆(A4 的威脅)要多強,才能把結果解釋掉。兩者都是通用工具,未針對此設計驗證。

第五種招式:看一條趨勢「被打斷」(中斷時間序列)

沒有控制組、沒有工具,只有一個結果在許多時間點上的追蹤,橫跨一個發生在已知時點的介入前後。 配出介入前的趨勢、外推當作反事實(沒介入本來會怎樣),再把效果讀成介入當下的水準跳變 與其後的趨勢改變。

先用白話想一遍

想像某縣市的每月健康負擔指數,兩年來緩緩上升。然後一個計畫上路。如果指數在那個月突然下降、 之後又下降得比以前快,這個「斷裂」就是介入留下的足跡,前提是:要不是有介入,這條線本來會 繼續沿著舊路走。整個方法的成敗,就押在那條外推的虛線,是不是『沒介入的未來』的公正猜測。

把名字拆開來看:「中斷」是中斷了什麼?

時間序列(time series)=一個結果在許多等間隔時間點上的連續紀錄(每月健康負擔指數),連起來就是一條隨時間的線。 中斷(interrupted)=在一個已知時點,介入像剪刀一樣切進這條原本順順的線,它把本來在跑的趨勢「打斷」。 整個方法就是:看序列在這個中斷點是不是跳一下(水準變化)、或轉個彎(斜率變化)。所以「中斷時間序列」= 一條被介入中斷的時間序列,在斷裂處讀出變化。

資料長什麼樣子?一條線、一個斷裂、一條虛線「假如」

灰點是每一期的結果。青色線是配適的趨勢,介入前(虛線豎線)一段、介入後一段。虛線把介入前 的趨勢延伸下去當反事實。介入後那條實線(或那些點)與虛線反事實之間拉開的落差,就是 ITS 效果: 一個立即的水準下降,加上更陡的斜率。

水準變化(β₂)

結果在介入當下的立即跳變,就在斷裂處一次性地往上或往下移。適合一上路就立刻發生的效果。

斜率變化(β₃)

介入後的趨勢改變,這條線現在是不是比以前升得/降得更快?適合隨時間累積的效果。

看專有名詞解釋

分段迴歸(中斷時間序列) segmented regression / ITS

某政策在一個已知時刻開啟,我們想知道我們追蹤的東西是不是因為它而改變。訣竅是:在開關打開之前觀察結果許多期,學出它原本就在走的趨勢,然後就把那條趨勢一路往後畫下去,那條延伸線就是「就算沒政策也會這樣」(反事實)。效果就是介入後的實際資料偏離那條線多遠。好處是只要一條序列,不必另設對照組,卻仍能把「突然跳一下」和「方向改變」分開。例子:每月住院數緩緩走了兩年,然後一個政策在第 24 個月上路。你配出前後兩段直線,寫成 Y_t = β₀ + β₁·t + β₂·X_t + β₃·(t−t₀)·X_t,其中 X_t 在開始時點 t₀ 之後打開(=1)。整件事成立的前提是:第 24 個月沒有發生別的事,這是唯一的大假設,你可以用加一條對照序列、或測試假的斷點來探查(Bernal, Cummins & Gasparrini 2017)。

水準變化與斜率變化 level change & slope change

一個政策能用兩種真正不同的方式推動結果,而 ITS 正是為了把它們分開而設計。水準變化是政策落地當下的瞬間階梯,線就在開始那一刻往上或往下跳,但之後的角度可能跟以前一樣。斜率變化是線爬升快慢的改變,沒有突然的跳,但從開始起線彎成更陡或更緩的路。這個差別很重要:一次性的階梯永遠那麼大、相對重要性會慢慢淡掉;斜率變化卻會一直累積、最後蓋過一切。例子:β₂ = −12 代表政策一開始住院數立刻掉 12;β₃ = −0.5/月 代表之後每個月再多掉半個,一年下來光斜率就又拿掉 6。式子裡 β₀ + β₁·t 是延伸的舊趨勢、β₂ 是那個立即階梯、β₃ 是那個轉彎。因為任一時點的總效果大約是 β₂ + β₃×(已過月數),你必須兩個都報,只講一個就藏了一半的真相。

自相關 autocorrelation

時間序列資料藏著一個陷阱:這個月的值通常和上個月綁在一起,所以相鄰的點不是各自獨立抽出來的。三月忙的醫院四月往往還忙;一個衝擊會延續、不會歸零。實際後果是:你真正獨立的資訊份數,比月份數少。為什麼要在意?因為每個信賴區間都建立在「獨立觀測的數目」上,若各月暗中一起動、你卻當它們各自獨立,公式就以為證據比實際多,誤差棒算得太窄,於是你把其實還在雜訊範圍內的效果,誤判成「顯著」。例子:一個住院數高的月份,後面往往又高;低的接著又低,正的月與月相關。正式說,它是模型剩下的殘差波動在鄰近時點之間還有相關,Corr(ε_t, ε_{t−k}) ≠ 0;效果估計本身沒問題,錯的只是它的不確定性。你可用 lag-1 殘差相關或 Durbin–Watson 檢查(見 ④)發現它,再去修誤差棒(見下方 HAC)。

Newey–West(HAC)穩健標準誤 Newey–West / HAC SE

一旦你接受各月份是相關的(自相關問題),解法不是去改效果估計,那不動,而是把誤差棒放寬到剛剛好的程度,讓它別再假裝資料獨立。Newey–West HAC 標準誤做的正是這件事:它重算不確定性、同時允許鄰近月份一起動,於是信賴區間長到它該有的寬度,你就不再誇大顯著性。可以把它想成對你「表面上的樣本數」課的一筆「相關稅」,你真正擁有的獨立資訊比月份數少,區間就得把這筆還回來。例子:未校正標準誤 1.2,考慮序列相關後可能變成 2.1,一個本來看起來明確顯著的效果就變成模稜兩可。這個方法(Newey & West 1987)之所以「穩健」,是因為你不必猜出確切的相關型態它也能用;若你確實知道型態(例如單純的月與月延續),改用 Prais–Winsten 或 ARIMA 直接建模它,可以得到更窄、更有效率的區間。

ITS 和 IV、RDD、DiD、TiT 有什麼不同?

其他方法都在比較『組』(處置 vs 對照、門檻上 vs 下、高採用 vs 低採用層)。ITS 比的是一個單位和它自己的過去: 反事實是外推的前趨勢,而不是另一組。這讓它便宜又通用,但它最大的單一風險是:介入的同時還發生了別的事。 控制組 ITS(⑤)借用 DiD 的邏輯,加一條對照序列,正是為了防這一手。

延伸閱讀:ITS 到底需要幾個時間點?(Zhang 2011 的模擬)

ITS 沒有像兩組試驗那樣一條現成的樣本數公式,因為它的檢定力同時取決於三件事:你有幾個時間點、效果相對於雜訊有多大、以及相鄰時間點之間的相關有多強。Zhang、Wagner 與 Ross-Degnan 針對分段自迴歸模型,每個情境模擬一萬組資料,把答案整理成表。

先看清楚他們怎麼定義效果量,因為它不是「變化了百分之幾」:效果量=(水準變化+每單位的趨勢變化)÷ 序列的標準差。同樣的絕對變化,落在一條上下震盪很大的序列上,效果量就會小很多。

效果量 1.0、介入前後點數相等、沒有自相關時,偵測單一參數(水準或趨勢其中之一)的檢定力大約是:12 點 45%、24 點 69%、48 點 93%、72 點 99%。正的自相關會把這些數字整排往下拉,因為彼此相關的點帶來的獨立資訊比較少;作者建議規劃時把自相關設在 0.1 到 0.5 之間,那是他們在真實政策評估裡看到的範圍。

表格裡有兩個直接可用的設計啟示。第一,把點數平均分在介入前後比一頭重一頭輕好:介入後只佔三分之一時,檢定力明顯下降。第二,小效果不會因為看得久就變好抓:他們的一個情境裡,60 個時間點、80% 檢定力,也只偵測得到 0.12 的絕對變化(相對約 20%)。

論文自己下的結論是:介入前後平均分配、總共 24 個時間點以上時,分段模型對效果量 1.0 以上多半有 80% 以上的檢定力(實際數字看自相關而定);低於這個規模、或預期效果較小,就要非常保守。他們建議的做法不是照表抄一個數字,而是照你自己的情境跑一次模擬。往 ② 互動那一頁,論文的十二張表已經做成可以點的查詢:填你預期的水準變化、趨勢變化與序列的標準差,它會先算出效果量,再告訴你達到 80% 檢定力最少需要幾個時間點。

出處:Zhang F, Wagner AK, Ross-Degnan D. Simulation-based power calculation for designing interrupted time series analyses of health policy interventions. Journal of Clinical Epidemiology. 2011;64(11):1252-1261. 若你的結果是計數資料(健康資料多半是),另見 Liu W 等人針對計數結果的版本:Contemporary Clinical Trials Communications. 2019;17:100474.

互動式 ITS:設定真實效果,看配適把它讀回來

拉動滑桿設定介入造成的真實水準變化。看分段迴歸配出兩段趨勢線、從前趨勢外推那條虛線反事實, 並把你設的水準(β₂)與斜率(β₃)讀回來,信賴區間來自對自相關穩健的(HAC)標準誤。

估計水準變化(β₂)
–
估計斜率變化(β₃)
–
真實斜率變化是 −0.6/期
追蹤結束時的效果
–
相對虛線反事實

點=觀察結果;實心青色=配適的前/後段;虛線=外推當反事實的前趨勢;豎點線=介入時點。 後段與虛線之間的垂直落差就是效果。

要幾個時間點才夠?(把 Zhang 2011 的模擬表做成可以點的)

論文用十二張模擬檢定力表回答這個問題。選你的情境,它直接把答案讀出來:達到你要的檢定力,最少需要幾個時間點。自相關用的是論文自己的 0.1 刻度,點數也是它模擬的那八個,所以這裡沒有任何超出原文的內插。

用你手上的數字把效果量算出來

這裡的效果量不是「掉了兩成」,而是變化相對於這條線本來就有多吵:(預期的水準變化+預期的每期趨勢變化)÷(結果在介入前趨勢周圍的標準差)。同樣的絕對變化,放在一條上下跳動很大的線上就不值錢。下面填你從自己的資料或文獻估得出來的數字。

這是論文 Figure 1 的可轉動版:在你選的情境下,檢定力隨自相關與時間點數變化的曲面。用滑鼠拖曳可以轉動。綠色平面是你要求的檢定力,曲面從平面下方穿上來的那條界線就是答案;紅點是上面那組設定。把自相關往正的方向看,會看到整片曲面明顯往下沉。

數字讀自 Zhang F, Wagner AK, Ross-Degnan D. J Clin Epidemiol 2011;64(11):1252-1261(AR(1) 表,每個情境一萬組模擬,顯著水準 0.05)。這是查表,不能取代照你自己的序列跑模擬:這些表假設一階自迴歸誤差與連續型結果。結果是計數資料的話,看 Liu 2019 那篇。

資料分析:跑一次完整的 ITS

載入內建的每月範例(或上傳含「期序、結果、介入後指標、介入後經過期數」的 CSV)。工具會用 HAC 標準誤配分段迴歸、畫反事實,並報告水準與斜率效果,附殘差自相關檢查。

或 尚未載入資料

程式(SAS · R · Stata):中斷時間序列

這是可直接在可下載的 its_sample.csv 上完整執行的程式(欄位:time、post、t_since、outcome)。

SAS — proc autoreg

/* read CSV */
proc import datafile="its_sample.csv" out=d dbms=csv replace;
    getnames=yes;
run;
/* segmented regression with autocorrelation correction */
proc autoreg data=d;
    model outcome = time post t_since / nlag=1 method=ml;
run;

time 是底層趨勢,post 是水準變化,t_since 是斜率變化;nlag=1 校正一階自相關。

R — lm 搭配 Newey-West

# segmented regression with autocorrelation-robust SE
library(lmtest); library(sandwich)
d <- read.csv("its_sample.csv")
fit <- lm(outcome ~ time + post + t_since, data = d)
coeftest(fit, vcov = NeweyWest(fit))
# plot observed series and fitted segments
plot(d$time, d$outcome, type = "p")
lines(d$time, fitted(fit))

post 捕捉中斷後的即時水準位移,t_since 捕捉斜率變化;NeweyWest 提供自相關穩健標準誤。

Stata — newey

* read CSV, set time, fit Newey-West segmented regression
import delimited "its_sample.csv", clear case(preserve)
tsset time
newey outcome time post t_since, lag(1)
* the user-written itsa command is a convenient alternative

newey 以 lag(1) 自相關穩健標準誤估計分段模型;使用者撰寫的 itsa 指令封裝了相同設計。

這個 ITS 可不可信?五道體檢

ITS 押在「外推的前趨勢是公正反事實」上,若介入同時還發生別的事就會失效(關鍵、不可檢驗)。 可檢驗的佐證:前趨勢夠線性、前後期數足夠、自相關已處理、介入時點明確。 綠燈沒問題、黃燈要留意、紅燈有狀況、藍燈需領域判斷。

載入中…

ITS 真正用到機器學習的那一個地方

因果機器學習一次看懂:從平均效果(ATE)到個體化效果(CATE)

超越單一平均效果。傳統方法估的是一個平均處置效果(ATE)。因果機器學習更進一步,瞄準個體化/條件效果(CATE):誰受益、受益多少。Meta-learners(S-/T-/X-/DR-learner)是與模型無關(model-agnostic)的套法,把彈性 ML 放進輔助模型(結果與傾向模型),而因果識別仍靠和本頁相同的假設,無未測混淆、重疊/正性、一致性。對真實世界資料(EHR、登錄)要小心:彈性 ML 能減少模型設定錯誤的偏誤,但救不了未測混淆,而且「預測得準」不等於「因果效果」。本頁 ⑤ 的示範正是這個想法的一個具體案例,用彈性 ML 處理輔助模型,識別仍來自設計。出處:Feuerriegel 等, Nature Medicine 2024;Kaddour 等, arXiv:2206.15475;Li & Chu 主編, Springer 2023。

ML 兩階段反事實(Dey 2025):當「沒介入會怎樣」非線性地取決於可觀測的共變項時, 用介入前資料訓練模型去預測它、再外推反事實。下面會真的在你的瀏覽器裡跑 scikit-learn (scikit-learn 是 Python 最常用的開源機器學習套件)。

為什麼這裡要 ML

「沒介入會怎樣」的結果,是由幾個可觀測的共變項非線性(含交互作用)地決定,而這些共變項的組合在介入後會漂移。 只看時間的未校正 ITS 會把共變項造成的變化誤當成介入效果;線性調整有幫助但抓不到交互作用; 梯度提升抓得到、把效果拉回真值。模型只看得到介入前的資料。

AI 藥方:ML 兩階段反事實(Dey 2025)

怎麼做:用過去訓練、預測反事實

另一種招式:把過去看得到的混淆減掉(事前事件率比)

會被接種的人,通常和沒接種的人不一樣,常常是風險較高(所以才被優先接種)。所以直接比較他們接種後的 事件率會被混淆。PERR 的招式:也比較兩組在還沒有人接種之前的事件率。事前期出現的任何率比落差 都是純混淆,把它從事後期率比中除掉:PERR =(事後率比)÷(事前率比)。

先用白話想一遍

想像處置組在接種前的事件率是對照組的 1.4 倍,但這時還沒有人接種,所以那個 1.4 純粹是混淆(處置組比較病重)。接種後,率比可能看起來約 1.0,好像沒效。但那其實是有保護力的疫苗 在對抗那個 1.4 的混淆。一除:1.0 ÷ 1.4 ≈ 0.72,疫苗其實把事件率降了約 28%。PERR 找出了未校正比較 藏起來的好處。前提是:這個混淆在兩段期間要一樣。

把名字拆開來看:「事前事件率比」

從後往前讀。率比(rate ratio)=處置組事件率 ÷ 對照組事件率。事件率=每人時發生幾次事件。 關鍵字是事前(prior):指「事前期,還沒有人接種之前的那段時間窗」。因為那時兩組都還沒接種, 事前期的率比就是純粹的混淆(兩組本來的差異)=一個乾淨的「指紋」。PERR 量這個事前率比、也量事後率比, 兩者相除把混淆消掉。所以「事前」=接種開始之前,拿來當混淆的基準線。

資料長什麼樣子?事前一道混淆落差、事後一個真效果

四個事件率:處置 vs 對照,分事前期與事後期。在事前期(還沒有人接種),青色棒就已經高過灰色棒, 那道落差就是混淆的指紋。在事後期,疫苗把處置組的率往下拉、把落差縮小。PERR 從這道落差怎麼 改變讀出效果,而不是只看事後的落差。

它估的是什麼

處置對事件的因果率比(≈相對風險),靠在比值尺度上消掉時間不變的混淆來還原,不需要量到那個干擾因子。

什麼時候勝過樸素世代研究

只看事後的樸素比較(如 Cox)會被每一個未測混淆汙染。PERR 把其中時間不變、乘法尺度的那部分消掉, 代價是需要一段乾淨的事前期,以及那份穩定性要成立。

看專有名詞解釋

率比 rate ratio (RR)

率比就是「每單位『暴露在風險中的時間』裡,事件在處置組發生的頻率是對照組的幾倍」。不能直接比原始事件數,因為兩組被追蹤的時間可能不一樣長;所以要先把每組的事件換成率(事件數 ÷ 人時,例如每 1000 人年幾件),再把兩個率相除。RR=1 代表沒差、大於 1 代表處置組事件較多、小於 1 代表較少。例如處置組每 1000 人年 30 件、對照組 20 件,RR = 30/20 = 1.5(高出 50%)。寫成式子就是 RR = (E_t / PT_t) ÷ (E_c / PT_c)。它是 PERR 最小的零件,方法在治療前算一個 RR、治療後算一個,整套只用它們的比值,所以「單一期的 RR」是後面一切的基礎。

事前事件率比(PERR) prior event rate ratio

未校正做法是治療後比「處置組 vs 對照組」的事件率,但病重的人本來就比較容易拿到藥、也比較容易出事,所以這個「只看事後」的比值被「病情」汙染了。PERR 的巧思是拿每組自己的過去當對照:先在治療前算一次處置 vs 對照的率比,這時還沒治療,所以這個比值純粹反映兩組本來的差距,再用治療後的率比去除以它,把本來的差距消掉,剩下治療真正的效果。寫成式子就是 PERR = 事後率比 ÷ 事前率比。它像「差異中的差異」的除法版,用同一批人的前後取代另設對照組。會失靈的地方:那個「本來的差距」要前後一樣大;若治療後病情自然好轉、差距變小,PERR 就會算錯。

時間不變的乘法性干擾(混淆)作用 time-invariant multiplicative confounding

這是 PERR 唯一被允許消掉的那種混淆,把它的意思弄懂,你就知道 PERR 什麼時候可信。時間不變=兩組本來的差距,治療前後一樣大(處置組治療後仍跟治療前一樣地相對病重)。乘法=它以固定倍數作用在事件率上(「多 1.25 倍」),而不是加上固定件數(「多 5 件」)。兩者都成立時,同一個倍數會出現在事前率比與事後率比裡,相除就乾淨地把它抹掉。例如處置組全程都是 1.25 倍事件傾向,那個 1.25 就相消;但若他們只在開始治療後才相對更病重,疾病本身在惡化,倍數就不再固定,PERR 會算偏。這是 PERR 的核心假設,它經典的失效情形(時變混淆、回歸均值、事件相依退出)全都是「前後不一樣」的那些狀況。

Delta 法信賴區間 delta-method CI

PERR 是由四個隨機事件數組成的比值,所以帶有不確定性,Delta 法 CI 就是替它加上誤差棒的方法。訣竅是在 log(對數)上做,除法在這裡變成減法:log(PERR) = log(事後率比) − log(事前率比) 只是簡單的加減,在這個尺度上四個事件數各貢獻一份獨立、好相加的變異。把它們加起來,取 ±1.96 個標準差的區間,再取指數還原成比值區間。有用的副作用:若事前期事件很少,它的變異項會暴增、CI 自動變寬,這是內建警報,告訴你這個估計是用太少資料算的。寫成式子就是 Var(log PERR) = Σ_各期 (1/E_t + 1/E_c),95% CI = exp(log PERR ± 1.96·√Var)。當計數很稀疏時,改用精確/profile 區間或配對 Cox(PERR-ALT)較安全,因為它們避開了這個罕見事件近似。

PERR 和 DiD、ITS 等有什麼不同?

PERR 是 DiD 的近親,兩者都把『事前的差異』從『事後的差異』裡減掉。差別:DiD 作用在結果的水準 (平均),PERR 作用在事件率比(每人時的次數),適合罕見事件與存活型資料;而且 PERR 的『事前』 是同一群人在接種前的窗,所以非常依賴混淆時間不變。一旦這點不成立,PERR 就會有偏,這正是分頁 ② 讓你親手體會的。

互動式 PERR:打破「時間不變」假設,看它怎麼歪掉

PERR 只有在混淆於事前、事後一樣時才成立。拉動滑桿,讓干擾因子的效果隨時間漂移 (例如體弱在接種後好轉)。在 0 時,PERR 還原真實率比 0.70。往上調,事前期就不再能代表事後的混淆, PERR 便偏離真值,儘管未校正比較從頭到尾都是錯的。

PERR(因果率比)
–
真正答案是 0.70
未校正:只看事後率比(有偏)
–
混淆掩蓋了效果
事前期率比(混淆指紋)
–
PERR 要除掉的東西

長條:事前期率比(混淆)、未校正事後率比、PERR。綠虛線是真值 0.70;灰虛線是 1.0(無關聯)。 漂移為 0 時 PERR 落在 0.70;漂移變大,它就往上爬離,你會親眼看到假設失效。

資料分析:跑一次完整的 PERR

載入內建的世代範例(或上傳每列一個人的 CSV:分組指標,以及事前/事後期的事件數與人時)。 工具會算事前、事後率比,PERR 及其 delta-method 信賴區間,與它所校正的未校正比較。

或 尚未載入資料

文獻提供的進階/精修(非 AI 的延伸)

① PERR-ALT(替代估計法,組內配對 Cox 似然)

不用兩個跨組率比,而是各組算自己的前→後率比再相除(配對 Cox)。在這些聚合率上點估計相同,但不需罕見近似,且更能處理配對資料與並列事件。

② PERR vs PERD(尺度敏感度)

若混淆是加法而非乘法,正確工具是事前事件率差(PERD)。兩者不可能同時對,把兩個都報出來當敏感度分析(下方計算)。

③ PERR-Comp(對退出穩健)

當退出/死亡因組而異,完成者一致的 PERR-Comp(Cheung & Ma 2025)仍近似無偏,只要退出不是事前事件直接造成。搭配 SCCS 與 DRIM 檢查(見 ④)。

可計算:PERR vs PERD 尺度敏感度

各自在對的尺度上發光

兩個合成世界。左:混淆是乘法,PERR(比值尺度)命中真實率比,PERD 是錯的尺度。 右:混淆是加法,PERD(差值尺度)命中真實率差,PERR 偏掉。教訓:把方法配上資料看起來的尺度, 另一個當敏感度分析。


程式(SAS · R · Stata):事前事件率比(PERR)

這是可直接在可下載的 perr_sample.csv 上完整執行的程式(欄位:pid、group、events_prior、pt_prior、events_post、pt_post)。

SAS — proc genmod Poisson

/* read CSV */
proc import datafile="perr_sample.csv" out=d dbms=csv replace;
    getnames=yes;
run;
/* prior-period rate ratio between groups */
data dp; set d; logpt = log(pt_prior); run;
proc genmod data=dp;
    model events_prior = group / dist=poisson link=log offset=logpt;
run;
/* post-period rate ratio; PERR = exp(beta_post)/exp(beta_prior) */
data da; set d; logpt = log(pt_post); run;
proc genmod data=da;
    model events_post = group / dist=poisson link=log offset=logpt;
run;

兩個帶對數人時偏移量的 Poisson 模型分別給出事前與事後的組間率比;兩者之比即為 PERR 校正後的效果。

R — Poisson glm 率比

# PERR = post rate ratio / prior rate ratio between groups
d <- read.csv("perr_sample.csv")
m_prior <- glm(events_prior ~ group, family = poisson,
              offset = log(pt_prior), data = d)
m_post  <- glm(events_post ~ group, family = poisson,
              offset = log(pt_post), data = d)
rr_prior <- exp(coef(m_prior)["group"])
rr_post  <- exp(coef(m_post)["group"])
perr <- rr_post / rr_prior
print(c(rr_prior = rr_prior, rr_post = rr_post, PERR = perr))

對數人時偏移量把計數轉為率;以事後率比除以事前率比,可移除時間穩定的干擾。

Stata — poisson exposure

* prior and post rate ratios via Poisson with person-time exposure
import delimited "perr_sample.csv", clear case(preserve)
poisson events_prior i.group, exposure(pt_prior) irr
poisson events_post  i.group, exposure(pt_post) irr
* PERR = post IRR / prior IRR (read the i.group IRRs from each model)

exposure() 提供人時;irr 報告組間率比。以事後 IRR 除以事前 IRR 即得 PERR 估計值。

這個 PERR 可不可信?五道體檢

PERR 依賴的假設大多無法只用資料檢驗(藍卡),並指出文獻真有的檢查。最關鍵的: 混淆時間不變且乘法。其餘:乾淨的事前期、無事件相依的處置或退出、以及足夠的事前事件數(唯一可檢項)。 綠燈沒問題、黃燈要留意、紅燈有狀況、藍燈需領域判斷。

載入中…

用 AI 強化 PERR:文獻目前還沒有

因果機器學習一次看懂:從平均效果(ATE)到個體化效果(CATE)

超越單一平均效果。傳統方法估的是一個平均處置效果(ATE)。因果機器學習更進一步,瞄準個體化/條件效果(CATE):誰受益、受益多少。Meta-learners(S-/T-/X-/DR-learner)是與模型無關(model-agnostic)的套法,把彈性 ML 放進輔助模型(結果與傾向模型),而因果識別仍靠和本頁相同的假設,無未測混淆、重疊/正性、一致性。對真實世界資料(EHR、登錄)要小心:彈性 ML 能減少模型設定錯誤的偏誤,但救不了未測混淆,而且「預測得準」不等於「因果效果」。本頁 ⑤ 的示範正是這個想法的一個具體案例,用彈性 ML 處理輔助模型,識別仍來自設計。出處:Feuerriegel 等, Nature Medicine 2024;Kaddour 等, arXiv:2206.15475;Li & Chu 主編, Springer 2023。

在其中三個方法,這個分頁能展示具體、已發表的 ML 升級。對 PERR,在來源論文裡 並沒有成熟的機器學習或雙重穩健版本的 PERR(最新的 Cheung & Ma 2025 是在釐清框架,不是 AI 方法)。 所以與其假裝有,不如說明文獻有什麼、沒有什麼,再加上清楚標示為推測的方向。文獻真正提供的 非 AI 精修(PERR-ALT、PERR vs PERD、PERR-Comp,以及尺度敏感度示範)已移到分頁 ③。

來源論文實際上有什麼

PERR 的論文(Yu 2012、Uddin 2015、van Aalst 2021、Rogers 2020、Cheung 2024、Cheung & Ma 2025) 都用古典率比/Cox 估計,搭配 delta-method 或自助法區間。這個文獻中沒有機器學習、沒有交叉擬合、 沒有雙重穩健的 PERR。這就是現況,不是我們會用漂亮 demo 掩蓋的缺口。

有沒有可能的「AI 藥方」?目前不知道,但有可能…

以下是我們謹慎的推測(可能的藥方,不是成熟的藥方),不是任何論文的結果。請當成研究方向,而非建議:

① 用 ML 估「事前期率」(推測)

用機器學習估事前期的事件率,或許能讓 PERR 要除掉的「混淆指紋」更銳利,就像 ML 傾向分數在別處的幫助。對 PERR 尚未驗證。

② 一條雙重穩健分數(推測)

把處置模型與結果模型配成一條雙重穩健分數,或許能減少對「混淆時間不變」假設(P1)的依賴,前提是能為此設計導出有效的正交分數,這仍是未解的問題。

③ E-value 式敏感度(推測)

E-value 式的敏感度分析或許能量化:混淆的時間變動要多大,才能把結果解釋掉。這是通用工具,未針對 PERR 驗證。

同一支疫苗,換個「時機」問題:早接種 vs 晚接種,以及不死時間偏誤的陷阱(CCW)

到目前為止我們問「疫苗有沒有效?」。現在換一個策略問題:診斷後,是早接種(在寬限期內)比較好, 還是延後?你不能照「最後做了什麼」分組來比,要能被歸到「早接種組」,你必須先活著、沒發生事件、 撐到去接種,於是早接種組憑空看起來更健康。這就是不死時間偏誤。解法是複製-設限-加權 (clone-censor-weight, CCW):一種針對「隨時間變動策略」的目標試驗模擬(Hernán 2018)。

怎麼做:複製、偏離就設限、再加權

看專有名詞解釋

動態治療策略 dynamic / sustained treatment strategy

一個「有沒有治療」的標籤只是一次性的快照,但真實的醫療是隨時間展開的,我們真正想比較的,是兩個「何時、要不要做」的規則,例如「診斷後 3 個月內接種」對上「不接種」。這就是動態(持續)策略:它告訴你在每個時點該怎麼做,而不是只貼一個是/否的標籤。我們想量的東西,也就是估計目標,就是「照規則 A 走」和「照規則 B 走」之間的結果差距。這個框架之所以重要,是因為「時機」的問題若硬塞進固定的「有暴露/無暴露」分組,就會偷偷帶進不死時間偏誤。這個想法源自 Hernán 等人(2006),他們用加權來比較這類隨時間變動的策略。

不死時間偏誤 immortal-time bias

要被分進「早接種組」,一個人得先活著、沒發生事件、一路撐到真的去接種,任何先發生事件的人,根本進不了這一組。於是還沒開始測量,早接種組裡自然擠滿了「存活者」,憑空看起來更健康;那段保證不會出事的時間,就是所謂的「不死時間」。它的危險在於:會讓「早開始」或「持續治療」看起來有保護效果,即使其實毫無作用,而拆穿這個假象,正是 CCW 存在的全部理由。一個典型的破綻:「曾經早接種的人」當然活夠久才去接種。解法是把時間零點、資格、指派三者正確對齊,這正是複製-設限-加權在做的事。

寬限期 grace period

在診斷當下(時間零點),我們還不知道誰最後算「早」、誰算「晚」,所以給一段短窗,也就是寬限期,記作 g,在這段期間,一個還沒接種、也還沒出事的人,和「早」「晚」兩種策略都真的相容。在 g 之內,這個人會被複製進兩個臂;「早」這條規則只要求他在 g 結束前接種就好。這就是 CCW 妥善處理「一開始誰屬於哪個策略」這個模糊地帶的方式,而不是靠猜。g 的長短(例如 3 個月)是會改變比較結果的真實設計選擇,所以必須事先講清楚,最好還要換不同的 g 試試、確認結論不是被 g 帶出來的,也就是對 g 做敏感度分析(見 ⑤)。

反設限機率加權 IPCW

當一個複製品違反了被指派的規則,我們就得把它從資料裡剪掉(設限),但這個剪法不是隨機的:較體弱、較年長的人比較容易偏離,於是留下來的存活者,並不能公平代表所有人。IPCW 的修正方式,是給每個存活的複製品一個權重,等於「它沒被設限的機率」的倒數(這機率由共變項估出來),於是一個本來很可能被剪掉的複製品,就代表了許多和它類似、卻被剪掉的人。大致上,權重 ≈ 1 ÷ P(維持遵循 | 共變項)。一個細節:grace 與早晚啟動情境用穩定化權重(分子是邊際機率,所以平均大約 1),而持續/停藥情境用未穩定化權重(分子就是 1,平均大於 1)再加截斷,這是無母數加權存活曲線的常見搭配。兩者都正確(見 ⑥)。記得肉眼檢查一下權重分布,看有沒有幾個超大的權重會主導結果(見 ④ 的 C4)。

CCW 和其他方法有什麼不同?

其他方法回答的是「點」問題(有沒有治療)。CCW 回答的是時機/持續策略問題(早接種 vs 晚接種), 而這裡未校正分析會中不死時間偏誤。它是一種目標試驗模擬:明確地把「你本來會做的試驗」建出來, 同樣的時間零點、資格、指派,再用複製+設限+加權取代隨機化。當問題是「何時開始」時,它就是最自然的工具 (Hernán 2018;García-Albéniz 等人;HIV 何時開始治療的研究)。

互動式 CCW:看 CCW 緊貼真值,未校正比較卻飄走

先選一個策略情境,每種都有自己的資料分布與估計目標。再拉動滑桿改變疫苗「真正」的保護力。 CCW(複製-設限-加權)在每個設定下都緊貼真實風險差;未校正比較則持續被不死時間/選擇偏誤帶偏。 看累積發生率曲線與三個數字一起變化。

CCW(複製-設限-加權)
–
應緊貼真值
真值(估計目標)
–
負值=早接種較保護
未校正比較(不死時間)
–
被帶偏離真值

早策略(青色)與晚策略(灰色)的加權累積發生率曲線。追蹤結束時兩條線的垂直落差就是 CCW 風險差。 把保護效果調高,早策略曲線就掉得離晚策略更低。

資料分析:跑一次完整的複製-設限-加權

載入內建的「早 vs 晚接種」範例(或上傳每列一個人的 CSV:何時接種、是否/何時發生事件、基線共變項)。 工具會把每個人複製到兩個策略臂、偏離就設限、配反設限機率權重,並把 CCW 風險差與帶有不死時間偏誤 的未校正比較並列。

或 尚未載入資料

程式(SAS · R · Stata):複製-設限-加權 CCW 的關鍵步驟

把每個人複製到兩個策略臂、偏離時設限、用 pooled-logistic 配 IPCW,再畫加權存活曲線。

這是可直接在可下載的 ccw_sample.csv 上完整執行的程式(每列一個人:pid, age, frailty, vacc_month〔NA=未接種〕、event, futime)。真實健保資料要先把領藥紀錄整理成每人一列;這份範例已經是該格式。

怎麼畫存活曲線:加權 KM vs 標準化(請先讀)

複製+IPCW 之後,你手上是一份帶時變權重的長格式(counting-process)資料。要得到每個策略的存活曲線有兩種正確做法,下面 R 程式兩種都附。
(1) 加權 Kaplan–Meier:把長格式直接丟給 survfit(Surv(tstart,tstop,event)~arm, weights=ipcw)。R 可以直接對長格式加權,所以這是最簡單、最常見的 CCW 曲線,當預設用。
(2) 標準化(g-formula):配一個 pooled-logistic 風險(hazard)模型,預測每個複製品逐月的存活,再在每個臂內對複製品取平均。當你還想直接校正共變項、正性(positivity)邊緣、或想要更平滑的曲線時,用這個。
兩者瞄準的是同一個邊際存活,結果應該一致。SE 注意:權重是估出來且時變的,所以天真的 KM/曲線標準誤是錯的;信賴區間請對 pid 做 bootstrap(或加權 Cox 用穩健 cluster(pid))。

把 IPCW 穩定化(用 baseline 當分子)。把穩定化的設限權重寫成一個比值:SW(t) = P(到 t 未被設限 | baseline V) / P(到 t 未被設限 | V 與時變共變項 L)。分母就是一般的 IPCW(去掉那些驅動偏離的時變因素造成的失衡)。分子就是你要乘上去的那個數:只用基線資訊 V 去看「你有多可能一直沒被設限」,它 ≤ 1,所以把過大的權重拉回 1 附近。效果:權重平均變成約 1,擬似人群和真實人群一樣大(變異變小),而且基線變數 V 的邊際分布維持在它時間零點的原始分布,所以加權後的人群仍然「長得像 baseline 的分布」,被修掉的只是時變的設限失衡。規則:放進分子的變數,一定也要放進結果/MSM 模型,因為基線穩定化只去掉時變混淆,你保留下來的 V 還在,必須在模型裡對它取條件。在 CCW 這通常無妨,因為複製本身已經讓兩臂在時間零點的 V 平衡了,所以這個基線穩定化主要只是用來馴服變異。

為什麼跑 PLR(pooled logistic)而不是 Cox?「time 放進去」又是怎麼回事(白話)

PLR 到底在做什麼(白話)。把每個人的追蹤切成一格一格(這裡是「人月」,一個月一列)。每一格問一個是非題:這個月有沒有發生事件?用邏輯斯迴歸預測「這個月發生事件的機率」,這個預測機率就是這一格的風險(hazard) h(k)。有了每格風險,把「每格活下來的機率」一路乘起來:S(t) = ∏(1 − h(k)),風險就是 1 − S(t)。因為每個月的風險和存活都算得出來,就能把整條曲線畫出來。

「把 time 放進去」是什麼意思。風險會隨追蹤時間變(常常剛開始高、後來降),所以把「時間」當自變數放進模型:可以放月份、月份平方(poly(month,2)),或每個月一個指標/樣條。這讓 baseline 風險能隨時間彎來彎去,而不是被逼成一條水平線。再加一個 arm × time 交互項,還能讓兩個策略的風險形狀不同。

為什麼這裡不用 Cox。CCW 想要的是加權後的存活曲線與絕對風險(例如 12 個月的風險差),不只是一個數。Cox 給你的是風險比(HR),也就是兩組風險的比值:它不可塌縮、本身不告訴你絕對風險,而且 baseline 風險「不指定形狀」偷偷帶過,要從它畫出乾淨的加權存活曲線很彆扭。PLR 則把風險明確建模成時間的函數,所以可以逐月預測每個複製品的存活、再平均(標準化/g-formula),正好得到我們要的曲線;時變 IPCW 權重在「人月」長格式裡也很自然地放進 PLR。而且幾乎不損失:當每一格的風險很小(月風險通常很小),PLR 和 Cox 幾乎一樣(D'Agostino 等 1990, Stat Med)。一句話:Cox → 一個 HR;PLR → 每月風險 → 存活曲線與絕對風險,而 CCW 要的正是後者。

SAS — 複製、設限、IPCW、加權存活(直接跑 ccw_sample.csv)

proc import datafile="ccw_sample.csv" out=d dbms=csv replace; getnames=yes; run;
%let g=3; %let H=12;                  /* grace period & horizon (months) */

/* 1) clone into both strategies, expand to person-months, mark deviation */
data pm; set d;
  vacc = (vacc_month ne .);
  stop = min(futime, &H);
  do arm = 1, 0;                       /* 1 = initiate within grace, 0 = defer */
    cens = 0;
    do month = 0 to stop-1 until(cens=1);
      tstart=month; tstop=month+1;
      evt = (event=1 and tstop=stop);
      acens = 0;
      if arm=1 and month=&g and not (vacc and vacc_month<=&g) then acens=1;
      if arm=0 and vacc and month=vacc_month and vacc_month<=&g then acens=1;
      output;
      if acens=1 then cens=1;          /* stop this clone after it deviates */
    end;
  end;
run;

/* 2) IPCW: pooled logistic for staying uncensored -> cumulative inverse weight */
proc logistic data=pm noprint;
  class arm; model acens(event='1') = arm month age frailty;
  output out=pc p=phat; run;
proc sort data=pc; by pid arm month; run;
data pm; set pc; by pid arm;
  retain cum; if first.arm then cum=1;
  cum = cum * (1 - phat);             /* P(still uncensored) */
  ipcw = 1/cum; run;

/* 3a) WEIGHTED survival curve per arm (the usual CCW curve) */
proc phreg data=pm covs(aggregate);
  class arm; model (tstart,tstop)*evt(0) = arm; weight ipcw; id pid;
  baseline out=km survival=s;          /* plot s by tstop, by arm */
run;

/* 3b) STANDARDIZATION: pooled-logistic hazard, then average predicted survival */
proc logistic data=pm noprint;
  class arm; model evt(event='1') = arm month month*month age frailty;
  output out=h p=hz; run;             /* per clone-month hazard; */
/* survival = cumulative product of (1-hz) by pid*arm, then mean by arm*month */

資料步驟做複製+人月展開,並在偏離當月停掉該複製品。proc logistic 給設限機率,其累乘的倒數即 IPC 權重。proc phreg … weight ipcw 配 baseline 畫加權存活曲線(3a);第二個 proc logistic 是標準化的風險模型,把預測存活平均起來就是 g-formula 曲線(3b)。

R 版本(參考實作):複製、IPCW、兩種存活曲線(直接跑 ccw_sample.csv)

# R — Clone-Censor-Weight (grace-period target-trial emulation)
# reads ccw_sample.csv: pid, age, frailty, vacc_month (NA=never), event, futime
library(dplyr); library(tidyr); library(survival)
d <- read.csv("ccw_sample.csv")
g <- 3; H <- 12                          # grace period & horizon (months)

# 1) clone into both strategies, expand to person-months, mark deviation
pm <- d %>% tidyr::crossing(arm = c("initiate","defer")) %>%
  group_by(pid, arm) %>%
  reframe(month = 0:(min(first(futime), H) - 1),
          across(c(age, frailty, vacc_month, event, futime), first)) %>%
  ungroup() %>%
  mutate(tstart = month, tstop = month + 1,
         vacc = !is.na(vacc_month),
         evt  = as.integer(event == 1 & tstop == pmin(futime, H)),
         acens = case_when(
           arm=="initiate" & month==g & !(vacc & vacc_month<=g)        ~ 1L,
           arm=="defer"    & vacc & month==vacc_month & vacc_month<=g  ~ 1L,
           TRUE ~ 0L)) %>%
  group_by(pid, arm) %>%
  filter(cumsum(lag(acens, default = 0)) == 0) %>% ungroup()  # drop post-deviation rows

# 2) IPCW: pooled logistic for staying uncensored -> stabilized weight
den <- glm(acens ~ arm + month + age + frailty, binomial, pm)
num <- glm(acens ~ arm + month,                binomial, pm)   # stabiliser
pm <- pm %>% mutate(pu = 1 - predict(den, type="response"),
                    pn = 1 - predict(num, type="response")) %>%
  group_by(pid, arm) %>% mutate(ipcw = cumprod(pn)/cumprod(pu)) %>% ungroup()

# 3a) WEIGHTED KAPLAN–MEIER on the long form (the usual CCW curve)
km <- survfit(Surv(tstart, tstop, evt) ~ arm, data = pm, weights = ipcw)
plot(km, col = c("#0E7C7B","#5b6b7b"), xlab="month", ylab="survival",
     main="CCW: weighted Kaplan–Meier")

# 3b) STANDARDIZATION (g-formula): pooled-logistic hazard, average over clones
hz <- glm(evt ~ arm*poly(month,2) + age + frailty, binomial, pm, weights = ipcw)
std_curve <- function(a){
  nd <- transform(pm, arm = a)
  nd$h <- predict(hz, nd, type = "response")
  nd %>% arrange(pid, month) %>% group_by(pid) %>% mutate(S = cumprod(1 - h)) %>%
    group_by(month) %>% summarise(S = mean(S), .groups = "drop")
}
ini <- std_curve("initiate"); def <- std_curve("defer")
lines(ini$month, ini$S, col="#0E7C7B", lty=2)   # dashed = standardized
lines(def$month, def$S, col="#5b6b7b", lty=2)

# CI: weights are estimated + time-varying -> bootstrap over pid (naive SE is wrong)

crossing+reframe 把每人複製成兩個策略、展開成人月;偏離後的列丟掉。兩個 pooled-logistic 給穩定化 IPC 權重。3a 把長格式直接丟給 survfit(..., weights=ipcw),就是加權 KM 曲線;3b 配風險模型、把每個複製品的預測存活平均起來,就是標準化曲線(虛線)。兩者應重疊;信賴區間請對 pid 做 bootstrap。

Stata — 複製、設限、IPCW、加權存活(直接跑 ccw_sample.csv)

* Stata — clone-censor-weight on ccw_sample.csv
import delimited "ccw_sample.csv", clear case(preserve)
local g 3
local H 12
gen vacc = !missing(vacc_month)

* 1) clone into both strategies, expand to person-months, mark deviation
expand 2
bysort pid: gen arm = _n - 1                 // 1 = initiate within grace, 0 = defer
gen stop = min(futime, `H')
expand stop
bysort pid arm: gen month = _n - 1
gen tstart = month
gen tstop  = month + 1
gen evt = (event==1 & tstop==stop)
gen acens = (arm==1 & month==`g' & !(vacc & vacc_month<=`g')) ///
          | (arm==0 & vacc & month==vacc_month & vacc_month<=`g')
bysort pid arm (month): drop if sum(acens[_n-1]) > 0   // drop post-deviation rows

* 2) IPCW: pooled logistic -> stabilized cumulative weight
logit acens i.arm month age frailty
predict pu, pr
logit acens i.arm month
predict pn, pr
bysort pid arm (month): gen ipcw = exp(sum(ln(1-pn))) / exp(sum(ln(1-pu)))

* 3a) WEIGHTED Kaplan–Meier / Cox (the usual CCW curve)
stset tstop [pw=ipcw], enter(tstart) id(pid) failure(evt==1)
sts graph, by(arm)                           // weighted survival curves
stcox i.arm, vce(cluster pid)

* 3b) STANDARDIZATION: pooled-logistic hazard + margins predicted survival
logit evt i.arm c.month##c.month age frailty
margins arm, predict(pr)                      // average predicted hazard per arm
* cumulate (1 - predicted hazard) over month for each arm to get the std curve

expand 把每人複製到兩臂、再展開成人月;偏離旗標 acens 截斷每個複製品。兩個 logit 組出穩定化 IPC 權重。3a stset [pw=ipcw]+sts graph 給加權 KM 曲線;3b pooled-logistic 風險配 margins 給標準化曲線。信賴區間:對 pid 做 bootstrap(權重是估出來且時變的)。

這個 CCW 可不可信?五道體檢

CCW 的核心假設大多無法只用資料檢驗(藍卡),這裡把可檢查的指標攤出來。最關鍵的: 「誰遵循哪個策略」無未測混淆。其餘:正性(最明確可檢的一項)、策略與寬限期定義清楚、權重模型合理、 時間零點對齊正確。綠燈沒問題、黃燈要留意、紅燈有狀況、藍燈需領域判斷。

CCW 擋得掉什麼、擋不掉什麼:基線 vs 寬限期之後

CCW 的兩個動作各擋掉一種偏誤。複製把每個人在時間零點同時放進兩個策略臂,所以兩臂在 t=0 完全相同,凡是「在基線就量得到」的適應症混淆 L₀都被自動平衡掉;偏離就設限+IPCW 再照基線共變項加權、補回因設限流失的人。合起來能乾淨處理基線的適應症混淆與不死時間偏誤。
但 IPCW 只看得到你放進權重模型的變數。如果「誰在寬限期內真的去接種」是被寬限期之後才出現的時變因素 Lₜ(例如病情惡化、新的檢驗結果)驅動,而 Lₜ 又會影響結果,這是時變混淆,在基線根本看不到,只靠 baseline 權重擋不掉,寬限期之後的偏離仍然被混淆。要處理它,得把 Lₜ 放進時變 IPCW(隨追蹤時間更新的權重)。Maringe 等(2020)與 Gaber 等(2024)都明確畫出這條界線。

左,基線混淆 L₀:複製讓兩臂在 t=0 完全相同、baseline IPCW 又依 L₀ 加權,後門關上(✓)。右,只在基線之後(寬限期內)才出現的混淆 Lₜ:baseline 權重看不到它,後門仍開著(✗,需時變 IPCW)。

載入中…

強化 CCW:精修(以及 ML 的位置)

因果機器學習一次看懂:從平均效果(ATE)到個體化效果(CATE)

超越單一平均效果。傳統方法估的是一個平均處置效果(ATE)。因果機器學習更進一步,瞄準個體化/條件效果(CATE):誰受益、受益多少。Meta-learners(S-/T-/X-/DR-learner)是與模型無關(model-agnostic)的套法,把彈性 ML 放進輔助模型(結果與傾向模型),而因果識別仍靠和本頁相同的假設,無未測混淆、重疊/正性、一致性。對真實世界資料(EHR、登錄)要小心:彈性 ML 能減少模型設定錯誤的偏誤,但救不了未測混淆,而且「預測得準」不等於「因果效果」。本頁 ⑤ 的示範正是這個想法的一個具體案例,用彈性 ML 處理輔助模型,識別仍來自設計。出處:Feuerriegel 等, Nature Medicine 2024;Kaddour 等, arXiv:2206.15475;Li & Chu 主編, Springer 2023。

複製-設限-加權的文獻並不以黑箱 AI 為核心;它真正的精修是關於設計與輔助(權重)模型。其中最重要、 也最能計算的,就是寬限期敏感度分析,所以我們直接做出來。下面再列出其他精修,包括「彈性/ML 權重模型」真正合適的位置。

可計算:答案如何隨寬限期變動

寬限期 g 定義了「早」是什麼,所以改變 g 會改變估計目標本身,不只是雜訊。把 g 從 1 跑到 5 個月。 CCW 在整段範圍都貼近真值;未校正(不死時間)比較則不會。這是任何 CCW 研究都該做的敏感度分析 (Hernán 2018;Gaber 等人 2024)。按下面看結果:

文獻中其他精修

① 彈性/ML 權重模型(搭配交叉擬合)

處置與設限的權重模型是輔助函數,可以用彈性/ML 學習器搭配交叉擬合來估計,就像 IV ⑤/DiD ⑤ 那樣。當共變項對時機是非線性關係時特別有用。估計式(複製-設限-加權)不變,只有權重模型變成資料自適應。

② 雙重穩健:IPW + g-formula

不要只靠加權,把反機率權重和一個結果(g-formula)模型結合成雙重穩健估計,只要權重模型或結果模型其一正確就一致。Smith & Hernán(2022)正是用這套 IPW+g-formula 來模擬持續策略的目標試驗。

③ 事先講清楚並檢驗設計

CCW 最大的進步不是來自更花俏的模型,而是來自正確指定的目標試驗:對齊的時間零點、資格、指派,事先講好的寬限期,以及正性檢查。報告寬限期敏感度(上方)與權重診斷(見 ④)。

這個方法的出處,依類型分的例子

方法/教學

Hernán(2018, BMJ),奠基性的複製-設限-加權想法(「死人不會偏離被指派的策略」)。Hernán 等人(2006),動態策略的 IPW。Maringe 等人(2020)與 Zhao、Lyu、Yoshida(2021),不死時間偏誤與 CCW 的彈性。Gaber 等人(2024, Cancer Medicine + Curr Epidemiol Rep),入門與實作。Webster-Clark 等人(2025),用合成資料做「接種時機窗」的 CCW(最貼近本示範)。Smith & Hernán(2022),持續策略模擬,IPW+g-formula。Emilsson 等人(2017, JAMA Oncology),揭露偏誤。

臨床應用

García-Albéniz 等人,前列腺癌「立即 vs 延後」雄性素剝奪治療(早 vs 晚)。HIV-CAUSAL 合作(2011, Ann Intern Med),何時開始合併抗反轉錄病毒治療。Larochelle 等人(2022, JAMA Netw Open),鴉片減量 vs 不變。Ju 等人(2024),心衰竭病人 statin 與癌症。Chen 等人(2024),睡眠呼吸中止的 β-blocker。Zhang 等人(Med Care),透析病人兩種貧血管理策略。全部都是「時機/持續治療」問題的目標試驗模擬。

病例交叉與病例-(病例-)時間對照:每個人當自己的對照

對一個可能由短暫暴露觸發的急性事件,比較同一個人在危險窗(事件前)vs 更早的參考窗的暴露, 用自己當對照,把所有穩定的個人特質都消掉(病例交叉,CCO)。麻煩在於:如果暴露的盛行率隨日曆時間上升, 近期那一窗本來就比較常暴露,CCO 會被高估。用同樣經歷趨勢的對照族群(或較晚發病的未來 case)把趨勢扣掉, 就是病例-(病例-)時間對照(CCTC)。

怎麼做:危險窗 vs 參考窗,加上上升的趨勢

看專有名詞解釋

病例交叉 case-crossover (CCO)

假設有人突然出事,比如心臟病發或跑急診,你懷疑是某個藥效短暫的藥引發的。與其去找別人來比,不如拿這個人跟「他自己」在兩個時間點比:事件發生前那一小段時間(「危險窗」)他有沒有在用這個藥,對上更早、什麼事都沒發生的一段平常時間(「參考窗」)?因為比的是同一個人,所有不會變的東西,基因、慢性病、生活習慣,自動被固定住,騙不了你。只有「兩窗不一樣」的人(一窗有用、一窗沒用)才真正提供資訊;兩窗都一樣的人什麼也說明不了。最後算出來的是這些「不一致對」的勝算比:OR_CCO = b/c,b 和 c 數的就是兩種不一致。這個自我配對設計由 Maclure(1991)提出。

暴露時間趨勢 exposure time trend

這就是會讓「單純病例交叉」失準的陷阱。假設這個藥這些年越來越流行,研究早期幾乎沒人用,後期一大堆人用。於是近期那一窗(危險窗)剛好落在藥很普遍的時候,較早的參考窗卻落在藥還很罕見的時候。結果一個人「事件前看起來比較常用藥」,純粹是因為日曆往前走了,不是藥真的做了什麼。這個假訊號會把病例交叉的答案往上推。舉例來說,使用率可能從早期的 10% 一路爬到後期的 40%。要抓這個陷阱,可以看一群「藥根本不可能影響到的人」:如果連他們的窗也是近期暴露比較多,也就是純趨勢 OR 大於 1,你就知道是日曆在搗鬼,不是藥。這正是下一個名詞要堵住的漏洞。

病例-時間對照/病例-病例-時間對照 case-time-control / case-case-time-control (CCTC)

修法的精神很簡單:在一群「藥不可能造成事件」的人身上,量出日曆趨勢到底有多大,再把這個趨勢從病例交叉的答案裡除掉,剩下的就只有真正的效果。最早的病例-時間對照(Suissa,1995)借一群「非 case」當趨勢的量尺。一個漂亮的變形,病例-病例-時間對照,改用「以後才會發病的人」(未來的 case)當量尺,因為他們同樣經歷那條日曆趨勢,但還沒對藥起反應;這樣就不必另外湊一條對照序列,也避開了「你對照到底選得對不對」這種沒完沒了的爭論。用數字看:如果原始病例交叉算出 6.1,但對照的純趨勢是 1.9,修正後的答案約為 6.1 ÷ 1.9 ≈ 3.2,很接近真值 3.0。寫成式子,就是一個勝算比除以另一個:OR_CCTC = (b_case/c_case) ÷ (b_ctrl/c_ctrl)。

互動:看暴露趨勢怎麼把病例交叉吹大

拉動滑桿,改變暴露盛行率隨日曆時間上升的陡度。在 0 時沒有趨勢,純病例交叉(CCO)本身就無偏; 往上調,CCO 就一路爬離真值,而CCTC(扣趨勢)穩住不動。看三個數字與暴露盛行率曲線。

病例交叉(CCO)
–
被趨勢吹大
CCTC(扣趨勢)
–
應緊貼真值 3.0
純趨勢 OR(對照)
–
趨勢指紋

曲線是各日曆月的暴露盛行率。趨勢調越大,它斜得越陡,CCO(被吹大)與 CCTC(≈3.0)之間的差距也越大。

資料分析:跑一次完整的 CCTC

載入內建的急性事件範例(或上傳每列一個個體的 CSV:case/對照旗標、危險窗與參考窗的暴露、日曆時間)。 工具會算病例交叉 OR、對照的純趨勢 OR,以及扣趨勢後的 CCTC OR 與 delta-method 信賴區間。

或 尚未載入資料

程式(SAS · R · Stata):病例-時間-對照

這是可直接在可下載的 cctc_sample.csv 上完整執行的程式(欄位:pid、group、cal_time、x_hazard、x_ref)。

SAS — 轉置 + STRATA 邏輯斯

/* read and reshape to two rows per subject */
proc import datafile="cctc_sample.csv" out=w dbms=csv replace;
    getnames=yes;
run;
data lng;
    set w;
    window=1; y=x_hazard; output;
    window=0; y=x_ref;    output;
run;

/* conditional logistic by subject, separately by group */
proc logistic data=lng;
    by group;
    strata pid;
    model y(event="1") = window;
run;
/* CTC OR = exp(beta_case - beta_control) */

依組別執行;以病例 OR 除以對照 OR 以去除時間趨勢。

R — 轉置 + clogit

# read wide data, build long form (2 rows per pid)
library(survival)
w <- read.csv("cctc_sample.csv")
lng <- rbind(
  data.frame(pid=w$pid, group=w$group, window=1, y=w$x_hazard),
  data.frame(pid=w$pid, group=w$group, window=0, y=w$x_ref))
# conditional logistic within each group
b_case <- coef(clogit(y ~ window + strata(pid),
                      data=lng[lng$group==1,]))["window"]
b_ctrl <- coef(clogit(y ~ window + strata(pid),
                      data=lng[lng$group==0,]))["window"]
# case-time-control OR removes exposure time-trend
cat("CTC OR =", exp(b_case - b_ctrl), "\n")

病例與對照窗 OR 之比即為校正時間趨勢的估計值。

Stata — reshape + clogit

* read and reshape to long form
import delimited "cctc_sample.csv", clear case(preserve)
gen id = _n
reshape long x_, i(id) j(win) string
gen window = (win=="hazard")
rename x_ y

* conditional logistic per group; ratio of ORs = CTC estimate
clogit y window if group==1, group(id) or
clogit y window if group==0, group(id) or

取病例窗 OR 除以對照窗 OR。

這個 CCTC 可不可信?五道體檢

核心假設大多無法只用資料檢驗(藍卡):短暫暴露、參考窗選得對、沒有不可測時間偏誤。明確可檢的是 不一致對數量是否足夠。綠燈沒問題、黃燈要留意、紅燈有狀況、藍燈需領域判斷。

載入中…

進階:病例-時間對照 vs 病例-病例-時間對照

因果機器學習一次看懂:從平均效果(ATE)到個體化效果(CATE)

超越單一平均效果。傳統方法估的是一個平均處置效果(ATE)。因果機器學習更進一步,瞄準個體化/條件效果(CATE):誰受益、受益多少。Meta-learners(S-/T-/X-/DR-learner)是與模型無關(model-agnostic)的套法,把彈性 ML 放進輔助模型(結果與傾向模型),而因果識別仍靠和本頁相同的假設,無未測混淆、重疊/正性、一致性。對真實世界資料(EHR、登錄)要小心:彈性 ML 能減少模型設定錯誤的偏誤,但救不了未測混淆,而且「預測得準」不等於「因果效果」。本頁 ⑤ 的示範正是這個想法的一個具體案例,用彈性 ML 處理輔助模型,識別仍來自設計。出處:Feuerriegel 等, Nature Medicine 2024;Kaddour 等, arXiv:2206.15475;Li & Chu 主編, Springer 2023。

兩者都消掉暴露趨勢偏誤;差別在用什麼當趨勢參考。按下面在同一筆(趨勢強)資料上並排比較,再看下面的取捨說明。

文獻中的注意事項

① 病例-時間對照(CTC)需要好的對照

CTC 用另一條非 case 對照序列估趨勢。若這些對照沒和 case 共享暴露趨勢、或被結果選擇,校正就錯。對照怎麼選是難點。

② 病例-病例-時間對照(CCTC)避開這點

CCTC 用較晚發病的未來 case 當趨勢參考,不需另一條對照序列,對「對照怎麼選」的批評較穩健(Wang & Hennessy)。前提是暴露趨勢對當前與未來 case 一樣。

③ 不可測時間偏誤仍要小心

若事件前暴露無法測得(如住院),危險窗會被扭曲(Jeong 2023;Wong 2025)。自身對照設計不修這個,要確認兩窗的暴露都被一致地測到。

序列試驗:每個資格時點開一場模擬試驗,再合併

當一個點治療(當下治療 vs 不治療)可以在很多不同時間點啟動時,你不能只比「曾治療 vs 從未治療」, 那會有不死時間偏誤(曾治療者必須先活得夠久才能開始)。做法:在每個資格月各模擬一場 小型目標試驗:在那一刻,比較啟動 vs 不啟動的人、對齊時間零點、調整基線共變項,再把所有序列試驗合併。 同一個人可在多場重複收案,放大有效樣本。

怎麼做:每個資格月開一場迷你試驗

看專有名詞解釋

序列試驗 sequential trials

一個「可以在很多不同時間點開始」的治療藏著一個陷阱:如果你只是拿「曾經用過藥的人」跟「從來沒用過的人」相比,曾用藥的那群人必須先活得夠久、撐到能開始用藥,這種「先天就活下來」會讓治療看起來比實際更有效(這就是不死時間偏誤)。解法是別把它當成一場大比較,而是每當有人符合資格,就開一場小型的假想試驗:在那一刻,把大家對齊在同一個起跑時鐘(時間零點),分成「現在開始」與「現在不開始」兩組,各自往前追蹤。一個月一個月地做,第 0 月一場、第 1 月一場……,再把各場的答案合併,讓越精準的試驗占越大份量(逆變異數加權)。因為同一個人可以重複符合資格、參加好幾場,你能從同一批人得到更多可用的資料。

點治療 vs 動態策略 point treatment vs dynamic strategy

這在問你「到底想問哪一種問題」。「點治療」是某一刻做出的單一是非決定:「我現在要不要開始?」,序列試驗正是為了回答這種問題而生。「持續」或「動態」策略則是一條你會一路遵守的規則:「只要符合某條件就一直用下去」,那是另一個分頁的 clone-censor-weight(CCW)法在處理的。具體說:「這位病人今天門診要不要接種?」是一次性的點問題(用序列試驗);「他往後幾年要不要持續打追加劑?」是持續的策略(用 CCW)。選對工具,其實就是先想清楚你真正的問題是「單一決定」還是「持續計畫」。不論哪一種,兩者都只是在模仿一場你實際上沒辦法跑的隨機試驗,也就是目標試驗模擬。

反機率加權(IPTW) inverse-probability-of-treatment weighting

在每一場迷你試驗裡,會開始用藥的人通常跟不用藥的人不是同一種人,例如體弱者往往比較早開始,所以直接相比並不公平(這叫適應症混淆)。IPTW 的解法是把人重新加權,讓兩組在你量得到的特徵上看起來一樣。做法是:先模型化每個人在其特徵 X 下「會開始用藥」的機率,再給每個人一個權重,等於那個機率的倒數,用藥者是 1/P(現在開始 | X),不用藥者是 1/P(不開始 | X)。一個本來很可能用藥、你卻剛好觀察到的人,就代表「很多個跟他類似的人」,於是稀有但有資訊的案例被放大、過度出現的被縮小,直到兩臂可比。每一場都這樣做,每場就能估出乾淨的治療效果。要注意:它只在「每一種人都有可能落到任一臂」時才成立,這就是正性檢查(見 ④ 的 C2)。

互動:序列試驗穩住目標,未校正比較卻飄走

拉動滑桿,改變治療被適應症混淆的程度(體弱者較早啟動)。序列合併估計在每個設定下都緊貼真值; 未校正的曾 vs 從未比較則整段都帶著嚴重的不死時間偏誤。看各場的風險差與數字。

序列(合併)
–
應緊貼真值
真值(點治療效應)
–
負值=治療有保護
未校正(曾 vs 從未)
–
有不死時間偏誤

每個點是一場序列試驗在其資格月的 IPTW 風險差(當下治療 vs 不治療);青線是它們的逆變異數合併估計;綠虛線是真值。 琥珀線是未校正的曾 vs 從未比較,遠在下方,被不死時間誇大。

資料分析:跑一次完整的序列試驗

載入內建的點治療範例(或上傳每列一個人的 CSV:何時啟動治療、是否/何時發生事件、基線共變項)。 工具會在每個資格月開一場序列試驗、做 IPTW、把各場效果做逆變異數合併,並與帶有不死時間偏誤的 未校正比較並列。

或 尚未載入資料

程式(SAS · R · Stata):序列試驗 Seq 的關鍵步驟

每個資格時點堆疊一場模擬試驗(時間零點歸零),再估計每個策略的存活。這裡偏好標準化;分層/加權 KM 當快速檢視。

這是可直接在可下載的 seq_sample.csv 上完整執行的程式(每列一個人:pid, age, frailty, init_month〔NA=從未啟動〕、event, futime)。

這裡怎麼畫存活曲線:偏好標準化(請先讀)

序列設計會把同一個人重複收進好幾場試驗,所以堆疊後的資料列彼此相關、重疊。直接在堆疊資料上對每個臂畫 Kaplan–Meier 會失真,因為同一段人時被多場試驗重複計入,且各場試驗的「啟動/未啟動」組成會漂移。
偏好:標準化(g-formula)。在堆疊的人時上配一個 pooled-logistic 風險(hazard)模型(納入試驗別與共變項),預測每個人在啟動 vs 不啟動下的存活,再對整個「試驗×人」族群取平均。即使有重疊,也能乾淨地瞄準邊際存活。
快速檢視:分層/加權 KM,在 Cox 裡用 strata(trial)、或每個臂各畫一條 KM,看個大概可以,但它承襲了堆疊失真,當參考即可。
兩者共同的 SE 注意:一個人出現在多場試驗,列彼此相關,請用個人叢集穩健 SE(cluster(pid))或對 pid 做 bootstrap;天真 SE 太窄。

SAS — 堆疊試驗、分層存活+標準化(直接跑 seq_sample.csv)

proc import datafile="seq_sample.csv" out=d dbms=csv replace; getnames=yes; run;
%let M=6; %let H=12;                       /* number of trials & horizon (months) */

/* stack one emulated trial per eligibility month; eligible = not yet */
/* initiated and still at risk at month m. time zero resets to m.       */
data trials; set d;
  do m = 0 to &M-1;
    if (init_month = . or init_month >= m) and futime > m then do;
      trial    = m;
      initiate = (init_month = m);        /* initiator at this trial's t0 */
      time     = min(futime, &H) - m;
      event2   = (event = 1 and futime <= &H);
      output;
    end;
  end;
run;

/* QUICK VIEW: stratified Cox, person-cluster-robust SE (repeat enrolment) */
proc phreg data=trials covs(aggregate);
  strata trial; model time*event2(0) = initiate age frailty; id pid;
run;

/* PREFERRED: standardization. Expand to person-time, pooled-logistic hazard */
data pt; set trials;
  do t = 1 to time; evt = (event2=1 and t=time); output; end;
run;
proc logistic data=pt noprint;
  class trial; model evt(event='1') = initiate t t*t age frailty trial;
  output out=h p=hz; run;
/* predict under initiate=1 vs 0, survival=cumprod(1-hz) by pid*trial, */
/* then average over the trial-person population at each t = std curve.  */

資料步驟每個資格月堆疊一場試驗(時間零點歸零)、標記啟動者。分層 proc phreg 搭 id pid 是快速檢視;人時展開+pooled-logistic proc logistic 是標準化的風險模型,把(啟動 vs 不啟動下)預測存活平均起來就是偏好的曲線。

R 版本:同樣步驟(每人一列 → 堆疊試驗 → 分層存活+個人穩健標準誤)

# R — sequential (nested) trial emulation on seq_sample.csv
library(dplyr); library(survival)
d <- read.csv("seq_sample.csv")
M <- 6; H <- 12                           # number of trials & horizon (months)

# stack one emulated trial per eligibility month; time zero resets to m
trials <- bind_rows(lapply(0:(M-1), function(m){
  d %>% filter(is.na(init_month) | init_month >= m, futime > m) %>%
    transmute(pid, trial = m, age, frailty,
              initiate = as.integer(!is.na(init_month) & init_month == m),
              time  = pmin(futime, H) - m,
              event = as.integer(event == 1 & futime <= H))
}))

# QUICK VIEW — stratified Cox, person-cluster-robust SE
fit <- coxph(Surv(time, event) ~ initiate + age + frailty +
               strata(trial) + cluster(pid), data = trials)
summary(fit)

# PREFERRED — standardization (g-formula) over the trial-person population
pt <- trials %>% filter(time > 0) %>% group_by(r = row_number()) %>%
  reframe(pid, trial, age, frailty, initiate, time, t = 1:time[1]) %>%
  mutate(evt = as.integer(event == 1 & t == time)) %>% ungroup()
hz <- glm(evt ~ initiate*poly(t,2) + age + frailty + factor(trial),
          binomial, pt)
std <- function(a){
  nd <- transform(pt, initiate = a); nd$h <- predict(hz, nd, type="response")
  nd %>% group_by(trial, pid) %>% arrange(t) %>% mutate(S = cumprod(1 - h)) %>%
    group_by(t) %>% summarise(S = mean(S), .groups = "drop")
}
s1 <- std(1L); s0 <- std(0L)
plot (s1$t, s1$S, type="l", col="#0E7C7B", ylim=c(0,1),
      xlab="month", ylab="survival", main="Sequential: standardized survival")
lines(s0$t, s0$S, col="#5b6b7b")          # initiate vs not, averaged
# CI: bootstrap over pid (rows correlated across trials)

lapply(0:(M-1), …) 每個資格月堆疊一場、時間零點歸零、標記啟動者。coxph 搭 strata(trial) + cluster(pid) 是快速檢視。人時展開+pooled-logistic glm、把(啟動 vs 不啟動下)預測存活對「試驗×人」族群取平均,就是偏好的標準化曲線;信賴區間對 pid 做 bootstrap。

Stata — 堆疊試驗、分層存活+標準化(直接跑 seq_sample.csv)

* Stata — sequential trial emulation on seq_sample.csv
import delimited "seq_sample.csv", clear case(preserve)
local M 6
local H 12

* stack one emulated trial per eligibility month (time zero resets to m)
expand `M'
bysort pid: gen trial = _n - 1
keep if (missing(init_month) | init_month >= trial) & futime > trial
gen initiate = (init_month == trial)
gen time  = min(futime, `H') - trial
gen event2 = (event==1 & futime <= `H')

* QUICK VIEW — stratified Cox, person-cluster-robust SE
stset time, failure(event2==1)
stcox initiate age frailty, strata(trial) vce(cluster pid)

* PREFERRED — standardization: expand to person-time, pooled-logistic hazard
expand time
bysort pid trial: gen t = _n
gen evt = (event2==1 & t==time)
logit evt i.initiate c.t##c.t age frailty i.trial
margins initiate, predict(pr)             // average predicted hazard per arm
* cumulate (1 - predicted hazard) over t per arm to get the std survival curve

expand `M' 堆疊試驗、保留符合資格的「人×試驗」;分層 stcox 是快速檢視。展開成人時、配 pooled-logistic logit 搭 margins 給標準化風險;每個臂把(1 − 風險)累乘即偏好曲線。信賴區間對 pid 做 bootstrap。

這個序列估計可不可信?五道體檢

核心假設大多無法只用資料檢驗(藍卡):各資格時點無未測混淆、時間零點對齊正確、序列試驗間無 carry-over。 正性與試驗/事件數則可檢。綠燈沒問題、黃燈要留意、紅燈有狀況、藍燈需領域判斷。

載入中…

進階:只用一場基線試驗 vs 合併所有序列試驗

因果機器學習一次看懂:從平均效果(ATE)到個體化效果(CATE)

超越單一平均效果。傳統方法估的是一個平均處置效果(ATE)。因果機器學習更進一步,瞄準個體化/條件效果(CATE):誰受益、受益多少。Meta-learners(S-/T-/X-/DR-learner)是與模型無關(model-agnostic)的套法,把彈性 ML 放進輔助模型(結果與傾向模型),而因果識別仍靠和本頁相同的假設,無未測混淆、重疊/正性、一致性。對真實世界資料(EHR、登錄)要小心:彈性 ML 能減少模型設定錯誤的偏誤,但救不了未測混淆,而且「預測得準」不等於「因果效果」。本頁 ⑤ 的示範正是這個想法的一個具體案例,用彈性 ML 處理輔助模型,識別仍來自設計。出處:Feuerriegel 等, Nature Medicine 2024;Kaddour 等, arXiv:2206.15475;Li & Chu 主編, Springer 2023。

只用第 0 月那一場、以及合併所有序列試驗,兩者都無偏,差別在效率。合併用到每個資格時點的人 (同一人可重複收案),讓區間更窄。按下面比較,再看說明。

文獻中的注意事項

① 個人叢集穩健標準誤

同一人在多場重複出現,列彼此相關。用個人叢集穩健 SE(或對人自助);未校正 SE 太窄。本工具提供個人叢集自助區間。

② 依計畫 vs 意向治療

每場序列試驗內可做意向治療(照基線選擇)或依計畫(偏離設限+IPCW,像 CCW)。兩者回答不同問題;要事先講清楚。

③ ML/雙重穩健的輔助模型

場內的傾向(與結果)模型是輔助模型,可用彈性/ML 學習器搭配交叉擬合來估、再雙重穩健地結合,就像 IV ⑤/DiD ⑤。合併方式不變。

這個方法的出處

方法與應用

Hernán & Robins,目標試驗框架。Danaei 等人與 Gran 等人,序列試驗模擬與合併估計。應用例:在懷孕用藥安全研究中,用目標試驗模擬避免不死時間(Epidemiology 2023;34(3):430-438)。當問題是多個資格時點的「當下治療 vs 不治療」時,序列試驗就是最自然的設計。

病例對照:從結果出發,回頭看暴露

世代研究要往前追蹤一大群人很多年。病例對照反過來做:找到有結果的人(病例)與沒有結果的人(對照), 再比較兩組過去的暴露,用勝算比(OR)衡量。對罕見結果特別有效率。危險在於混淆:這裡年齡同時推動 暴露與結果,所以未校正 OR 會偏;校正(或配對)年齡就能還原真相。現代視角(Dickerman & Hernán):一個有效的 病例對照,等於對「模擬目標試驗的世代」做病例對照抽樣。

怎麼做:病例 vs 對照,回頭比暴露

看專有名詞解釋

勝算比 odds ratio (OR)

病例對照研究是從「已經得病的人(病例)」和「沒得病的人(對照)」出發,回頭問:哪一組過去比較常有暴露?「勝算」就是一組裡「有暴露人數 ÷ 沒暴露人數」。勝算比把兩組的勝算相除,病例的暴露勝算除以對照的暴露勝算。OR=2 表示病例暴露的勝算是對照的兩倍;等於 1 就代表沒關聯。把資料排成 2×2 表(病例 a、b,對照 c、d),算式很單純:OR = (a·d)/(b·c)。好用之處在於:當疾病罕見時,這個 OR 幾乎等於一個規模大得多的前瞻研究會算出的風險比,所以小而省力的病例對照,照樣能還原我們想知道的效果。

混淆 confounding

有時候暴露和疾病看起來有關,其實只是因為背後偷偷有第三個東西同時影響兩邊。這裡那個東西是年齡:年長者本來就既較常暴露、又較容易生病。所以你直接比較病例與對照的暴露時,那段差距有一部分根本不是暴露造成的,只是病例剛好比較老。這就是為什麼「未校正 OR(沒校正的)」會偏大、還不是真正的因果效應。修法是讓兩組在那個第三因子上條件相同:用 logistic 模型校正年齡、切成年齡分層再以 Mantel–Haenszel 合併、或把對照按年齡配對到病例。要注意,這只能清掉你真的量到的混淆;若有沒量到的(例如吸菸),答案仍可能偏掉。

配對與條件式分析 matching & conditional analysis

配對是在「挑對照」這一步就直接處理混淆:替每個病例,刻意挑在干擾因子上長得像它的對照(例如同年齡層、同性別),讓兩組在這些因子上無從差別。但一旦你硬把兩組配成一樣,分析時也得照這個方式做,在每個配對組「內部」比較,而不是把所有人混在一起比,否則 OR 會被拉向 1(看起來沒效果)。在成對配對下,只有「不一致對」(一個有暴露、一個沒有)才帶訊息,配對勝算比就是這兩種不一致對的比值:OR_matched = b/c。一條鐵律:只配在真正的干擾因子上。如果配在「暴露所造成的東西(中介)」或「共同結果(對撞因子)」上,反而會引入偏誤,而不是消除它。

互動:看混淆怎麼把未校正 OR 推來推去

拉動滑桿,改變年齡對暴露的影響有多強(混淆強度)。在 0 時沒有混淆,未校正 OR 本身就等於真值; 往上調,未校正 OR 一路爬離真值,而校正年齡後的 OR 穩住不動。校正能修掉量得到的混淆。

未校正 OR
–
被年齡混淆
校正年齡 OR
–
應緊貼真值 2.0
真值
2.0
真實因果 OR

未校正 OR 與校正 OR 隨混淆強度的變化。調越大,未校正 OR(琥珀)越爬離真值,校正 OR(青)穩停在虛線真值上。

資料分析:未校正 vs 校正 vs 分層 OR

載入內建病例對照範例(每列一個人:case/對照旗標、暴露、共變項含年齡)。工具會算未校正 OR、校正 年齡/性別/共病的 logistic OR,以及按年齡層×性別分層的 Mantel–Haenszel OR,並顯示讓未校正 OR 出錯的年齡不平衡。

或 尚未載入資料

程式(SAS · R · Stata):配對病例對照、條件式邏輯斯迴歸

出處 — 程式碼即各套件官方文件的標準呼叫:R survival 套件的 clogit()(見 survival 套件手冊與 clogit 說明頁)、SAS PROC LOGISTIC 的 STRATA 敘述(SAS/STAT 手冊條件式邏輯斯範例)、Stata clogit 指令(Stata Base Reference Manual: clogit)。

這是可直接在可下載的 cc_sample.csv 上完整執行的程式(欄位:pid、match_id、case、exposed、age、sex、comorbidity、age_band)。

SAS — PROC LOGISTIC STRATA

/* read the sample CSV */
proc import datafile="cc_sample.csv" out=d dbms=csv replace;
    getnames=yes;
run;

/* conditional logistic via STRATA on the matched set */
proc logistic data=d;
    strata match_id;
    model case(event="1") = exposed comorbidity;
run;

STRATA match_id 讓 PROC LOGISTIC 配適條件式概似。

R — survival::clogit

# read data and fit conditional logistic regression
library(survival)
d <- read.csv("cc_sample.csv")
fit <- clogit(case ~ exposed + comorbidity + strata(match_id),
              data = d)
print(summary(fit))
# exposed coefficient gives the matched odds ratio

clogit 以 match_id 為條件;exp(coef) 即配對勝算比。

Stata — clogit

* read data
import delimited "cc_sample.csv", clear case(preserve)

* conditional logistic grouped by matched set
clogit case exposed comorbidity, group(match_id) or

or 選項以 95% 信賴區間報告配對分析的勝算比。

這個病例對照可不可信?五道體檢

核心假設大多關於研究設計、無法只用資料檢驗(藍卡):對照能代表來源族群、暴露兩組量得一樣準、配對與 時間零點設對。可檢的是未校正 OR 被混淆多少、以及各格人數夠不夠。綠燈沒問題、黃燈要留意、紅燈有狀況、藍燈需領域判斷。

載入中…

用 AI 強化:配對病例對照的隨機森林

因果機器學習一次看懂:從平均效果(ATE)到個體化效果(CATE)

超越單一平均效果。傳統方法估的是一個平均處置效果(ATE)。因果機器學習更進一步,瞄準個體化/條件效果(CATE):誰受益、受益多少。Meta-learners(S-/T-/X-/DR-learner)是與模型無關(model-agnostic)的套法,把彈性 ML 放進輔助模型(結果與傾向模型),而因果識別仍靠和本頁相同的假設,無未測混淆、重疊/正性、一致性。對真實世界資料(EHR、登錄)要小心:彈性 ML 能減少模型設定錯誤的偏誤,但救不了未測混淆,而且「預測得準」不等於「因果效果」。本頁 ⑤ 的示範正是這個想法的一個具體案例,用彈性 ML 處理輔助模型,識別仍來自設計。出處:Feuerriegel 等, Nature Medicine 2024;Kaddour 等, arXiv:2206.15475;Li & Chu 主編, Springer 2023。

當暴露效應只在某亞群出現(暴露 × 共變項的交互作用)、且某共變項 以非線性方式作用時,只放主效應的條件 logistic 會抹平這個結構。為配對病例對照量身的隨機森林(Matched Forest/ CLogitForest)能抓到它,留出集 AUC 較高,變數重要度也標出效果修飾子。

文獻中的注意事項

① 配對資料的 ML 要顧到配對結構

一般 ML 無法處理配對病例對照的條件式結構。Matched Forest 加入反事實、CLogitForest 在條件 logistic 上長樹/森林,這才讓它們在這裡有效(Shomal Zadeh 2020;Schauberger 2024)。

② ML 找的是結構,不是免費午餐

森林在「有非線性與交互作用可找」時才幫得上忙。若只是單純的線性主效應,條件 logistic 一樣好、且更好解釋,用 ML 探索效應修飾,再報一個清楚的估計。

③ 混淆仍要靠設計

AUC 較高的森林仍修不了選擇偏誤、回憶偏誤、未測混淆,那些是設計問題(對照、時間零點、配對)。ML 讓分析更銳利,但救不了有偏的設計。

自身對照病例系列(SCCS):每個人當自己的對照,只要 case

一支疫苗會不會在接種後短暫提高某個急性事件(如心肌炎)的風險?SCCS只用發生過事件的人(cases), 讓每個人當自己的對照:把他的觀察期切成接種後的危險窗(這裡 1–28 天)與其餘的基線期,比較兩段的 事件速率,用條件 Poisson 算相對速率(IRR)。因為是同一個人前後比,所有不隨時間變的因子(基因、體質、 社經)都自動被消掉。

怎麼做:把每個 case 自己的時間切成「控制期 vs 危險窗」

這樣讀:每一條是一個 case 的觀察時間。灰色=這個人自己的控制期;橘色=接種 ▲ 後那一小段危險窗(暴露人時)。SCCS 只問事件 ● 落在哪裡,是落在短短的危險窗(病人甲、乙、丁),還是落在控制期(病人丙)。若事件相對集中在「時間很短」的危險窗,IRR 就升高。因為是拿一個人跟自己比,所有不隨時間變的因子(基因、體質、社經)都自動相消。

看專有名詞解釋

自身對照病例系列 self-controlled case series (SCCS)

安全性研究最怕的是:打疫苗的人本來就和沒打的人不一樣(基因、健康、生活習慣),結果出事的其實是這些差異、不是那一針。SCCS 乾脆繞開這件事:它只收真的發生過事件的人(例如所有得到心肌炎的人),改問另一個問題,在同一個人自己的時間軸上,事件比較容易落在「打針之後那一小段」,還是平均散落在其他時間裡?因為是拿一個人跟自己比,凡是不隨時間改變的東西,基因、體質、收入,在前後兩段裡完全一樣,自動被消掉,所以根本不必另找一組對照。例子:mRNA 一劑後的心肌炎(Lai 等 2024)。方法出自 Farrington 1995,好讀的教學見 Whitaker, Farrington & Musonda 2006。

危險窗與相對速率 risk window & incidence rate ratio (IRR)

疫苗的風險(若有)通常是「短暫」的,集中在打針後幾天,然後就消失。所以我們把那一小段圈起來當危險窗(這裡是接種後 1–28 天),其餘時間都算這個人的基線期。接著數:危險窗裡平均每天發生幾件事,跟基線期每天幾件比,這兩個「速率」的比值就是相對速率(IRR)。IRR 等於 1,代表危險窗跟平常一樣安全;IRR 等於 3,代表打針後事件發生得快三倍。因為窗很短,它能精準抓出那個「短暫的凸起」,而不會被整段追蹤期稀釋掉。算式上,一個人的事件落在危險窗而非基線的機率是 P(事件落危險窗) = e_risk·IRR / (e_base + e_risk·IRR),其中 e_risk、e_base 是他待在兩段的時間長度。

條件 Poisson conditional Poisson

  • 一個人一個人分開算。把每個人的事件總數當成已知(知道他在自己的時間軸某處發生了事件),只問一件事:在這個前提下,那件事是落在危險窗、還是基線?
  • baseline hazard 會自己消掉。每個人自己的 baseline hazard(那個看不見、人人不同的背景風險)在條件概似的分子與分母同時出現,互相抵銷,根本不進入估計。所以人與人之間所有不隨時間變的差異(基因、體質、社經)依設計消失。
  • 會隨時間變的東西不會自動相消。年齡增長、季節更替是真的會沿著一個人自己的時間軸改變速率的,所以我們把每條時間軸也切成年齡段或季節段一起估。
  • 最大化的條件概似:log L = Σ [xᵣβ + log eᵣ − log Σⱼ eⱼ exp(xⱼβ)]。
大師原典與軟體資源:官方網站 sccs-studies.info 全紀錄

方法源頭與維護者 origin & people

SCCS 方法由 Paddy Farrington(Open University,現為榮譽教授)開發。Open University 的共同開發與貢獻者: Heather Whitaker(UK Health Security Agency;網站維護者,heatherjwhitaker@gmail.com)、 Yonas Ghebremichael-Weldeselassie(Open University;R 套件作者)、Patrick Musonda(University of Zambia)、 Mounia Hocine(Public Health France)。SAS 程式由 Bart Spiessens 與 Francois Haguinet (GSK Biologicals, 比利時)貢獻。官方網站:sccs-studies.info (Home · R · STATA · SAS · About)。

專書與教學論文 book & tutorials

專書:Farrington P, Whitaker H & Ghebremichael-Weldeselassie Y. Self-Controlled Case Series Studies: A Modelling Guide with R. Chapman & Hall/CRC Biostatistics Series。
教學論文:Whitaker HJ, Farrington CP & Musonda P. Tutorial in Biostatistics: the self-controlled case series method. Statistics in Medicine 2006; 25(10): 1768–1797。
綜論:Petersen I, Douglas I & Whitaker H. Self-controlled case series methods — an alternative to standard epidemiological study designs. BMJ 2016; 354: i4515。

R 軟體 R software

CRAN 套件 SCCS(v1.5,2021-12-11;作者 Yonas Ghebremichael-Weldeselassie), cran.r-project.org/package=SCCS。 模型:標準 SCCS · 半參數 SCCS · 事件相依觀察期 · 事件相依暴露(pseudolikelihood)· 平滑年齡效果(樣條)· 平滑暴露效果(樣條)· 全樣條 SCCS。內含教學資料集(midat、siddat、rotdat、bupdat、opvdat、nrtdat、rsvdat、 pmdat、bpdat、febdat、amdat、apdat、condat、itpdat、intdat、gbsdat、autdat、adidat、hibdat、addat、dtpdat、 gidat、hipdat)、樣本數計算器、資料模擬與 clogit 重整工具。條件式擬合可用 gnm、 survival::clogit(事件分層)或 cyclops。OMOP/CDM 資料:OHDSI SelfControlledCaseSeries (GitHub)。教學範例:MMR/腦膜炎(Oxford)、ITP 與 MMR(多重危險窗)、腸套疊與口服小兒麻痺(重複暴露)。

STATA 軟體 STATA software

用標準 STATA 配條件 Poisson(取代舊的 aglm.ado): xi: xtpoisson nevents i.exgr i.agegr, fe i(indiv) offset(loginterval)。 範例 do-file 與資料集:oxford.dta/oxford.do(MMR 與腦膜炎);itp.dta/itp.do(多重危險窗)、 itp_non_ind.do(非獨立事件);intuss.dta 搭配 intuss_analysis1–6.do 與 intuss_interact.do (共變項/交互作用)。半參數:oxford_sp.do、itp_sp.do、intuss_sp.do(Farrington & Whitaker 2006)。 設限/截斷的事件後暴露:intuss_censored.do、intuss_cens_pseudo.do(含自助法信賴區間;Farrington, Whitaker & Hocine 2009)。

SAS 軟體 SAS software

三個巨集(SAS v8.0+,Spiessens & Haguinet 提供):SCCS.sas 建立病例系列資料集(v9.4 修正版 sccsdta_symbol_replaced.sas);Poisreg.sas 用 Newton–Raphson 配 Poisson 迴歸(可消因子加速); element.sas 由變數清單產生巨集變數。全域參數:agerange(如 0 730 天)、risk (如 0 6 7 14)、age 切點、season 切點、semi=Y 半參數。教學範例(參數與半參數、附 .lst 輸出): Oxford MMR 與腦膜炎(Miller 等, Lancet 1993);ITP 與 MMR(Miller 等, 2001);OPV 腸套疊(Andrews 等, 2001)。 延伸:設限/擾動的事件後暴露(Farrington 等, 2009)、個體間不同的危險窗長度。

SCCS 延伸與實務判斷:當標準假設不成立時

標準 SCCS 建立在四條假設上;專書與 SCCS R 套件為每一條被威脅時提供一個延伸。以下每張卡把延伸與一個真實範例結合,並展示資料長相與配適它的 SAS code。個人內設計的核心優勢,它消掉所有時間不變、人與人之間的混淆(如抗憂鬱藥與髖部骨折:SSRI 比 TCA 多出的風險其實是體弱病人、不是藥;Hubbard 等 2003),正是每個延伸要守住的東西。(Farrington、Whitaker & Ghebremichael-Weldeselassie 2018;sccs-studies.info;範例改寫自 Douglas 2023,引用原始論文。)

① 事件相依暴露(短期/長期):違反是「暫時」還是「永久」?
何時用/判斷

事件本身改變了日後暴露。永久(心肌梗塞讓 statin 永遠停掉):無法補救,別用 SCCS。暫時(抽搐短暫延後下一劑疫苗;輪狀病毒疫苗 vs 腸套疊):加一段暴露前危險窗 [−τ,0),把被偏的時間移出基線;若它的 RR ≠ 1,就代表暴露是事件相依的。長期相依要用反事實暴露史+估計方程式求解(書 §7.1)。

資料長相
長格式,一個人切成多段;危險窗之前多加一段「暴露前」。
pid區段expgr事件數loginterval
7暴露前 [−14,0)pre0log 14
7危險窗 [1,28]risk1log 28
7基線base0log 300
SAS code
proc genmod data=sccs;  class pid expgr;
   model nevents = expgr / dist=poisson link=log offset=loginterval;
   repeated subject=pid;            /* condition on the person */
   /* expgr levels = base / pre / risk; test exp(pre)=1: an LRT vs a model
      without 'pre' checks short-term event-dependence (Farrington book §5.4). */
run;
/* Long-term dependence: R SCCS::eventdepenexp() — counterfactual exposure + EE. */
② 事件相依觀察期/SCRI :設限、死亡與變動的背景
何時用/判斷

事件相依觀察期。事件截短了追蹤(升高死亡率,或結果就是死亡)。標準 SCCS 會偏;用「事件→結束」間隔對概似加權、迭代擬合(Farrington 等 2011)。設限校正可能翻盤(抗精神病藥與中風讓某亞群從 1.31 變 1.05)。背景盛行率在變時,可把陽性檢驗的 RR 除以同窗陰性檢驗的 RR(陰性對照式校正:活動出席與 COVID-19)。

SCRI 是一種設計選擇,不是上面問題的補救。自身對照風險區間(SCRI)就是一種 SCCS,只是兩段期間都由你自己事先定義:暴露後的一段短風險區間,以及一段另外選定的控制區間(例如暴露前的一段定義好的窗、或暴露後很久的一段),兩者都相對於接種日。你不必把整個剩餘的研究期都當成基線。因為控制區間短、且擺在暴露附近,SCRI 也順帶避開了長期的背景時間趨勢與多數事件相依觀察的問題,這也是它在疫苗安全研究常見的原因(見 Vaccine 2024)。

資料長相
同長格式,另記「事件→觀察結束」的間隔(這裡死亡截短了追蹤)。
pidexpgr事件數loginterval事件→結束
12risk1log 289
12base0log 1109
SAS code
/* SCRI: keep only a pre-defined risk interval vs a pre-defined control */
/* interval near exposure (not the whole study period), then a plain SCCS. */
proc genmod data=scri;  class pid expgr;
   model nevents = expgr / dist=poisson link=log offset=loginterval;
   repeated subject=pid;
run;
/* Event-dependent observation (incl. death): R SCCS::eventdepenobs() weights
   the likelihood by the event→end interval and fits it iteratively. */
③ 年齡/季節(樣條/非參數基準)
何時用/判斷

基準率有尖峰(嬰兒抽搐在某年齡達峰;季節性感染)。少數年齡切點太粗:把 age/season 切更細,或用樣條基底欄取代切點,讓時變基準平滑。

資料長相
更細的年齡帶(或樣條基底欄 s1,s2,…)取代少數粗切點。
pidexpgragegr事件數loginterval
3basea40log 30
3riska51log 14
3basea60log 30
SAS code
/* fine age bands as a class factor (or spline columns s1-s4 as effects). */
proc genmod data=sccs;  class pid expgr agegr;
   model nevents = expgr agegr / dist=poisson link=log offset=loginterval;
   repeated subject=pid;          /* agegr soaks up the seasonal/age baseline */
run;
④ 劑量/連續與環境暴露
何時用/判斷

暴露是劑量/強度、不是有無(劑量反應:血壓與頭痛),或每段一個共享的環境水準(空污與氣喘;氣溫與 RSV)。用連續暴露項(log-linear 劑量反應)取代 0/1 指標。

資料長相
暴露欄帶劑量/水準數值,不只是 0/1。
pid劑量/水準事件數loginterval
500log 60
5100log 30
5401log 30
SAS code
proc genmod data=sccs;  class pid;
   model nevents = dose / dist=poisson link=log offset=loginterval;
   repeated subject=pid;          /* exp(dose) = RR per unit dose (log-linear) */
run;
⑤ 多劑量/多暴露型/多型事件
何時用/判斷

每人多個暴露起點(重複/間歇,NSAID 與消化道出血;DTP 多劑與抽搐),或事件不只一種亞型(熱性 vs 非熱性抽搐)。每個暴露各給一個指標/窗;多型事件則分層或用多項概似。

資料長相
重複暴露→每人多個危險窗列(risk1、risk2、…)。
pidexpgr事件型事件數loginterval
9risk1熱性1log 14
9base熱性0log 90
9risk2熱性0log 14
SAS code
proc genmod data=sccs;  class pid expgr;
   model nevents = expgr / dist=poisson link=log offset=loginterval;
   repeated subject=pid;          /* expgr = base/risk1/risk2/... one RR per window */
   /* multi-type events: add 'where evttype=...' strata, or a multinomial model. */
run;
⑥ 主動對照 SCCS :時變適應症混淆
何時用/判斷

標準 SCCS 消掉時間不變的混淆,但消不掉時變的適應症混淆(促使開藥的疾病也讓結果率變動)。納入一個同適應症對照藥的第二暴露欄;主動對照 RR = exp(β藥 − β對照) 把它差掉(glitazone vs sulphonylurea 與骨折;Hallas 2021、Schultze 2025)。

資料長相
兩個暴露欄,藥與主動對照藥(互斥或 nested 危險窗)。
piddrugcomp事件數loginterval
21101log 28
21010log 28
21000log 250
SAS code
proc genmod data=sccs;  class pid;
   model nevents = drug comp / dist=poisson link=log offset=loginterval;
   repeated subject=pid;
   estimate 'active-comparator RR' drug 1 comp -1;   /* exp(b_drug - b_comp) */
run;
⑦ 初次 vs 盛行暴露 :盛行使用者也會稀釋 SCCS 的估計(Jung 2025)
何時用/判斷

SCCS 消掉時間不變的混淆,但不能免疫於盛行使用者偏誤。Jung 等(PDS 2025)顯示把暴露定義成盛行(而非初次/新使用)會把 IRR 往虛無值稀釋,氟喹諾酮與視網膜剝離從 1.83 → 1.70,機制是易感者耗竭。實務原則:盡量用初次暴露+夠長的洗除期,並報告敏感度。

資料長相
由洗除窗加一個「首次使用」旗標;切段前只留初次(incident=1)暴露。
pid首次處方洗除乾淨?incident
312019-03是1
322019-05否(先前用過)0
SAS code
/* keep INCIDENT exposure: first-ever fill with a clean washout, THEN run SCCS. */
proc sql;
   create table incident as select * from rx
   where first_fill = min_fill and prior_use_in_washout = 0;   /* new user */
quit;
/* then split incident exposures into intervals and fit the SCCS as above; */
/* report the IRR under incident vs prevalent definitions as a sensitivity check. */
⑧ 設計、檢定力與可辨識性(分析之前)
何時用/判斷

規劃階段,危險窗、年齡組與觀察期的選擇決定每人被切成幾段,也決定檢定力、以及效果是否可辨識。用公式或模擬估樣本數/檢定力,檢查效率,並考慮用 SCRI 作為務實設計。

資料長相
規劃輸入(還沒有資料),候選危險窗、預期 RR、事件數、觀察長度。
危險窗目標 RR事件數觀察(天)
1–28 天2.0300365
1–14 天2.0300365
SAS/R code
/* Power by simulation: generate SCCS data under a target RR, fit, repeat, */
/* and record the % of runs that reject — vary the risk window & #events.   */
/* R: SCCS::sccssim()/power helpers; SAS: a %macro looping the genmod fit.  */

互動:SCCS 對「時間不變的混淆」免疫

拉動滑桿改變健康接種者選擇的強度(會去接種的人本來就比較健康,一個時間不變、人與人之間的混淆)。 「人與人之間」比較的未校正速率比會被拉偏;而同一個人前後比的 SCCS IRR 不動如山,因為每個人都是自己的對照。

未校正人際速率比
–
被選擇混淆
SCCS IRR(個人內)
–
應緊貼真值 3.0
真值
3.0
真實因果 IRR

健康接種者選擇越強,未校正速率比(琥珀)越滑離;SCCS IRR(青)平貼在虛線真值上,因為個人內設計把時間不變的混淆消掉了。

資料分析:跑一次 SCCS(條件 Poisson 的 IRR)

載入內建的 case(每列一個發生過事件的人:觀察期起訖、接種日、事件日)。工具會把每個人切成危險窗 (接種後 1–N 天)與基線期,配條件 Poisson 的 IRR 與 95% 區間。

或 尚未載入資料

程式(SAS · R · Stata):自身對照病例系列

出處 — 程式碼即官方文件的標準呼叫:R 使用 SCCS 套件的 standardsccs(),參數(indiv/astart/aend/aevent/adrug/aedrug)同 SCCS 套件手冊與 vignette;SAS 為 PROC GENMOD 以 log(人時) 為 offset 的 Poisson 標準寫法(SAS/STAT GENMOD 手冊);Stata 為 xtpoisson, fe exposure() irr(Stata Longitudinal-Data Reference Manual: xtpoisson)。

這是可直接在可下載的 sccs_sample.csv 上完整執行的程式(每位 case 一列;欄位:pid、obs_start、obs_end、vacc_day、event_day、age_grp)。三種語言都會在內部把每位 case 展開成區間的 long form,且都用同一個危險窗=接種後第 1 到 28 天。

SAS — 條件式 Poisson(PROC GENMOD)

/* read data */
proc import datafile="sccs_sample.csv" out=d dbms=csv replace;
    getnames=yes;
run;

/* expand each case into a 28-day post-dose risk window vs baseline */
data lng;
    set d;
    /* pre-dose baseline (the dose day counts as baseline) */
    risk=0; ystart=obs_start;   yend=vacc_day;
    intlen=yend-ystart+1; ev=(ystart<=event_day and event_day<=yend);
    loglen=log(intlen); if intlen>0 then output;
    /* risk window = days 1..28 after vaccination */
    risk=1; ystart=vacc_day+1;  yend=min(obs_end,vacc_day+28);
    intlen=yend-ystart+1; ev=(ystart<=event_day and event_day<=yend);
    loglen=log(intlen); if intlen>0 then output;
    /* post-window baseline */
    risk=0; ystart=vacc_day+29; yend=obs_end;
    intlen=yend-ystart+1; ev=(ystart<=event_day and event_day<=yend);
    loglen=log(intlen); if intlen>0 then output;
run;

/* conditional Poisson (subject fixed effects) */
proc genmod data=lng;
    class pid;
    model ev = risk / dist=poisson link=log offset=loglen;
run;

risk 係數為受試者內的對數相對速率(IRR)。

R — SCCS::standardsccs

# read data and fit the SCCS model
library(SCCS)
d <- read.csv("sccs_sample.csv")
fit <- standardsccs(event ~ vacc_day,
          indiv = pid, astart = obs_start, aend = obs_end,
          aevent = event_day, adrug = vacc_day + 1,
          aedrug = vacc_day + 28, data = d)
print(fit)
# exp(coef) is the IRR in the 28-day post-dose risk window

standardsccs 配適條件式 Poisson SCCS 並印出相對速率(IRR)。

Stata — xtpoisson, fe

* build 3 intervals/case: risk window = days 1..28 after dose
import delimited "sccs_sample.csv", clear case(preserve)
expand 3
bysort pid: gen seg = _n
gen risk = (seg==2)
gen lo = cond(seg==1, obs_start, cond(seg==2, vacc_day+1, vacc_day+29))
gen hi = cond(seg==1, vacc_day,  cond(seg==2, min(obs_end,vacc_day+28), obs_end))
gen intlen = hi - lo + 1
gen ev = (event_day>=lo) & (event_day<=hi)
drop if intlen<=0

* fixed-effect (conditional) Poisson by subject
xtset pid
xtpoisson ev risk, fe exposure(intlen) irr

固定效果 Poisson 以各受試者為條件,得到相對速率(IRR)。

這個 SCCS 可不可信?五道體檢

核心假設大多關於研究設計(藍卡):事件不可改變日後暴露、不可中斷觀察(事件要罕見/可復發)、危險窗要選對、 時變因子要靠切分處理。可檢的是危險窗裡的事件夠不夠。綠燈沒問題、黃燈要留意、紅燈有狀況、藍燈需領域判斷。

互動:一次打破一個假設,看 IRR 怎麼被帶偏

SCCS 出錯的三種方式,各附上論文裡會遇到的術語。這些名字只是簡稱、不一定精準,重點是每張卡上寫的機制。 選一種違反、把滑桿拉大,比較三個數字:內建的真值(IRR=2.0)、違反之下的天真 SCCS、以及用標準解法處理後的估計。

SCCS 只做一件事:比較「危險窗內每千人日幾件事」和「基準期每千人日幾件事」。這個「每千人日幾件」就是臨床上說的發生率(本頁叫它密度)。下面看三種讓這個比被動手腳的方式。

有顏色=資料看得到的;灰色鬼影=真實世界發生過、但資料看不見的。SCCS 只能用有顏色的部分計算。

圖為 12 人示意;記分板數字用約 400 人的期望值計算,所以不會跳格。

怎麼處理:每一招都畫在同一條時間線上

延伸閱讀:事件相依的正式解法 PD-SCCS(Simpson 2013)

標準 SCCS 是條件 Poisson 模型(conditional Poisson),它假設同一個人身上的事件彼此獨立地發生,上面第 ③ 種違反打破的就是這一條。Simpson 提出的 PD-SCCS(positive dependence SCCS,正向事件相依模型)保留 SCCS 的骨架,但允許「發生一次事件之後,接下來的風險會被抬高」,用一個參數 δ 描述抬高的幅度;δ=0 時就退回一般的 SCCS。

兩個關鍵的實用性質:第一,個人的基線參數一樣會從條件概似裡消掉,不必逐人估計,所以在上千萬人的理賠資料庫裡照樣跑得動;第二,δ=0 可以直接檢定(單尾 Wald 檢定,並用 AIC/BIC 在兩個模型間取捨),也就是說「這份資料的相依性到底要不要緊」是可以由資料回答的,不必憑感覺。

為什麼值得在意:論文的模擬顯示,相依性強的時候,一般 SCCS 不只是精確度變差,它的 95% 信賴區間覆蓋率會掉到 84% 以下(最差的設定只有 57.7%),而 PD-SCCS 仍接近名目水準。真實資料上兩者也會分岔:rofecoxib 與心肌梗塞的相對發生率(relative incidence),SCCS 估 1.17、PD-SCCS 估 1.29。

什麼時候用:結果會復發、而且一次發作看起來確實會招來下一次的情境(癲癇、跌倒、心肌梗塞),尤其是上市後安全監測(postmarketing surveillance)這種把每次事件都計入、而不是只取第一次的分析。要注意它只解決相依性這一條,事件相依暴露與事件相依觀察期(上面第 ① 與第 ② 種違反)仍然要各自處理。

出處:Simpson SE. A positive event dependence model for self-controlled case series with applications in postmarketing surveillance. Biometrics. 2013;69(1):128-136.

① 人被篩過 → 基準期的 ✕ 被帶走 → IRR 虛胖(高估)。
② 時間被剪短 → 基準期的天數被剪掉 → IRR 被壓低(低估)。
③ 事件會傳染 → 兩邊都被灌票、基準期灌更多 → IRR 被稀釋(拉向 1)。
這個比要乾淨,需要三樣原料老實:人沒被挑過、時間沒被剪短、事件彼此無關。三個情境,就是三樣原料各被動了一次手腳。

載入中…

用 AI 強化:自身對照 × 機器學習,找出高風險亞群

因果機器學習一次看懂:從平均效果(ATE)到個體化效果(CATE)

超越單一平均效果。傳統方法估的是一個平均處置效果(ATE)。因果機器學習更進一步,瞄準個體化/條件效果(CATE):誰受益、受益多少。Meta-learners(S-/T-/X-/DR-learner)是與模型無關(model-agnostic)的套法,把彈性 ML 放進輔助模型(結果與傾向模型),而因果識別仍靠和本頁相同的假設,無未測混淆、重疊/正性、一致性。對真實世界資料(EHR、登錄)要小心:彈性 ML 能減少模型設定錯誤的偏誤,但救不了未測混淆,而且「預測得準」不等於「因果效果」。本頁 ⑤ 的示範正是這個想法的一個具體案例,用彈性 ML 處理輔助模型,識別仍來自設計。出處:Feuerriegel 等, Nature Medicine 2024;Kaddour 等, arXiv:2206.15475;Li & Chu 主編, Springer 2023。

標準 SCCS 只回一個平均 IRR;但若危險窗的風險其實因人而異 (只在某亞群很高),平均值就把它藏起來。把每個人的自身對照標籤(事件有沒有落在危險窗)交給隨機森林 (Xu 等 2022 的 self-matched learning 精神),就能找出誰是高風險,個人化決策規則的起點。

文獻中的注意事項

① 核心 SCCS 不是 ML 方法

標準 SCCS 是條件 Poisson 模型,沒有機器學習。ML 角度是近期且特定的:針對效應異質性/決策規則的 self-matched learning(Xu 等 2022),以及疫苗安全訊號偵測的高維正則化 SCCS。

② 異質性 ≠ 隨意挖亞群

ML 找到的亞群要事先指定或交叉驗證,否則會挖到雜訊。報告這是探索,並在新資料上確認亞群 IRR 再據以行動。

③ SCCS 的假設仍然要顧

自身對照的 ML 仍承襲 SCCS 的假設(事件不改變日後暴露、暴露短暫、時變因子切分)。ML 精修「對誰有效」,但不會放鬆設計假設。

主動對照新使用者(ACNU):A 的新使用者 vs 對照藥 B 的新使用者

新藥 A 會不會提高某個結果的風險?拿用 A 的人 vs 沒用藥的人比會雙重偏誤:病情重的才會被開 A (適應症混淆),而沒用藥的人通常比較健康(健康使用者偏誤)。主動對照新使用者設計改成比 A 的新使用者 vs 主動對照藥 B(治療同一個適應症)的新使用者:兩組都有這個病、都從明確的時間零點 (第一張處方)起跑,適應症混淆與不死時間/盛行使用者偏誤就大幅消掉;殘留的嚴重度差再用傾向分數補掉。

為什麼 A vs B 勝過 A vs 沒用藥:A 與 B 的嚴重度很接近

看專有名詞解釋

主動對照新使用者 active-comparator, new-user (ACNU)

想知道新藥 A 會不會造成傷害時,最直覺的比法是「用 A 的人 vs 沒用藥的人」,但這兩群人除了藥以外,健康狀況差很多,比出來的結果會誤導。ACNU 用兩個動作修正。第一是「主動對照」:不拿 A 跟「沒人」比,而是拿 A 跟另一個治同一種病的藥 B 比,這樣兩群人都真的有這個病、健康底子也接近。第二是「新使用者」:每個人都只從他「第一張處方」開始算,大家的時鐘都從同一點起跑(不讓已經吃很久的人佔便宜)。例子:一顆全新的糖尿病藥 A vs 一顆老牌糖尿病藥 B,每個人都從第一次吃開始追蹤。最後若 A、B 兩群人病情還有一點點差距,再用統計補乾淨。(新使用者概念:Ray 2003;主動對照新使用者:Lund, Richardson & Stürmer 2015。)

適應症混淆 confounding by indication

做藥物研究最棘手的地方是:醫生會開某個藥,理由通常是「病人比較嚴重」,而病情本身又會自己把結果往上或往下推。於是當「病重的人拿到新藥、本來就比較容易出事」時,你根本分不清多出來的事件是藥造成的、還是只因為這些人一開始就病得重,藥的效果和病情糾纏在一起了。這個糾纏就叫「適應症混淆」,是藥物安全研究裡最大的陷阱。ACNU 聰明的地方在於:挑一個治同一種病的對照藥 B,兩組人「生病的理由相同」,所以還沒開始校正,這層糾纏就已經大半互相抵消了。

新使用者設計 new-user design

意思就是:每個人都只從他「這輩子第一張」處方開始算,大家的碼表都在同一種起跑點歸零。為什麼要這樣?如果你改成把「現在剛好正在用藥的人」也撈進來,等於偷偷只挑到了存活者,早早就吃出問題的人早退出了,還在吃的人看起來比實際健康(這叫「盛行使用者偏誤」)。這樣做也避開了「不死時間」,那種按定義根本還不可能出事的追蹤時段,會憑空假造出一個「保護效果」。實際做法:把研究窗開始前就已經在用藥的人排除掉,每個人都從第一劑開始計時。

互動:主動對照一開始就少偏很多

拉動滑桿改變疾病嚴重度左右「拿 A 還是 B」的程度(適應症混淆)。未校正的 A vs 沒用藥速率比就算在零也已經 嚴重偏高(健康使用者偏誤的落差);ACNU 未校正 A vs B 一開始就近很多、只隨混淆變強才漂;校正嚴重度後的 ACNU 穩在真值。

未校正:A vs 沒用藥
–
適應症+健康使用者偏誤
ACNU 未校正:A vs B
–
較不偏(都有病)
ACNU 校正後
–
應緊貼真值 1.6

資料分析:跑一次 ACNU(速率比,A vs 主動對照藥 B)

載入內建世代(每列一個人:drug=A/B/none、疾病嚴重度、追蹤人時、是否發生事件)。工具會算未校正的「A vs 沒用藥」速率比、 ACNU 未校正的「A vs B」速率比,以及校正嚴重度後的 ACNU(Poisson 速率模型),各附 95% 區間。

或 尚未載入資料

程式(SAS · R · Stata):主動對照新使用者世代 Cox 比例風險

出處 — 程式碼即 Cox 模型的官方標準呼叫:R 使用 survival 套件的 coxph() 與 survfit()(見 survival 套件手冊與 “Using Time Dependent Covariates / survival vignettes”);SAS 為 PROC PHREG 的 model 敘述(SAS/STAT PHREG 手冊);Stata 為 stset/stcox 與 estat phtest(Stata Survival Analysis Reference Manual: stcox)。設計概念另見 Lund、Richardson 與 Stürmer 2015。

這是可直接在可下載的 acnu_sample.csv 上完整執行的程式(欄位:pid、drug、severity、age、comorbidity、futime、event)。

SAS — PROC PHREG Cox 模型

/* read the sample CSV */
proc import datafile="acnu_sample.csv" out=d dbms=csv replace;
    getnames=yes;
run;

/* Cox PH: drug effect adjusted for confounders */
proc phreg data=d;
    class drug (ref="0");
    model futime*event(0) = drug severity age comorbidity / risklimits;
    hazardratio drug;
run;

PROC PHREG 配適 Cox 模型並印出風險比與 95% 信賴區間。

R — survival::coxph

# read data and fit Cox PH
library(survival)
d <- read.csv("acnu_sample.csv")
fit <- coxph(Surv(futime, event) ~ drug + severity + age + comorbidity,
             data = d)
print(summary(fit))
# plot baseline survival
plot(survfit(fit), xlab = "Follow-up time", ylab = "Survival")

coxph 估計校正後的 drug 風險比;summary 提供信賴區間。

Stata — stset / stcox

* read data and declare survival time
import delimited "acnu_sample.csv", clear case(preserve)
stset futime, failure(event)

* Cox PH with hazard ratios
stcox i.drug severity age comorbidity
estat phtest, detail

stcox 報告風險比;estat phtest 檢驗比例風險假設。

這個 ACNU 可不可信?五道體檢

核心假設大多關於研究設計(藍卡):對照藥要同適應症、兩組都要是新使用者且時間零點對齊、對照藥對結果要中性。 可檢的是 A 與 B 的嚴重度平不平衡、事件數夠不夠。綠燈沒問題、黃燈要留意、紅燈有狀況、藍燈需領域判斷。

載入中…

用 AI 強化:機器學習傾向分數

因果機器學習一次看懂:從平均效果(ATE)到個體化效果(CATE)

超越單一平均效果。傳統方法估的是一個平均處置效果(ATE)。因果機器學習更進一步,瞄準個體化/條件效果(CATE):誰受益、受益多少。Meta-learners(S-/T-/X-/DR-learner)是與模型無關(model-agnostic)的套法,把彈性 ML 放進輔助模型(結果與傾向模型),而因果識別仍靠和本頁相同的假設,無未測混淆、重疊/正性、一致性。對真實世界資料(EHR、登錄)要小心:彈性 ML 能減少模型設定錯誤的偏誤,但救不了未測混淆,而且「預測得準」不等於「因果效果」。本頁 ⑤ 的示範正是這個想法的一個具體案例,用彈性 ML 處理輔助模型,識別仍來自設計。出處:Feuerriegel 等, Nature Medicine 2024;Kaddour 等, arXiv:2206.15475;Li & Chu 主編, Springer 2023。

主動對照削掉大半混淆後,A 與 B 之間還有殘留混淆要用傾向分數(PS)校正。當「拿 A 還是 B」的決定和共變項是 非線性關係(嚴重度 × 年齡的閾值交互作用)時,只放主效應的邏輯斯 PS 設定錯誤、校正不乾淨;改用 梯度提升 PS(hdPS/ML-PS 的精神)抓到非線性,把速率比拉回真值。

文獻中的注意事項

① 設計做了大半的事

主動對照新使用者設計靠設計本身消掉適應症混淆與不死時間(immortal time),還沒建模就先成立。ML 傾向分數只是把 A 與 B 之間殘留的嚴重度差補掉。

② ML-PS 要有重疊、要確實驗證

彈性 PS 會過擬合;要檢查共變項重疊(正性)、截斷極端權重、加權後再看平衡。AUC 高不是目的,共變項平衡才是。

③ 估的是 A『相對 B』

就算 PS 完美,估的仍是 A 相對於對照藥 B 的效應,不是相對於「沒用藥」。要挑對結果中性的對照藥,否則把它的效應納入解讀。

盛行新使用者(PNU):把盛行使用者納回來,又不落入耗竭偏誤

乾淨的純新使用者設計只比 A、B 的新起始者,但會丟掉所有盛行(既有)使用者,樣本變小、代表性差。 可是若直接把盛行使用者和新起始者合在一起比,就會落入易感者耗竭:容易出事的人早就出事、退出了, 留下來還在用 A 的盛行使用者是低風險存活者,而且已經度過起始後的高風險期。PNU(Suissa 2017)用時間條件配對, 依距起始時間對齊、再用時間條件傾向分數,把盛行使用者不偏地納回來。

易感者耗竭:盛行 A 使用者是低風險存活者

看專有名詞解釋

盛行新使用者 prevalent new-user (PNU)

「新使用者」是指我們從他第一次開始用藥那天起追蹤的人;「盛行使用者」則是早就在用了的人。最乾淨的研究只用新使用者,但這會丟掉所有已經在用藥的人,剩下又小又不具代表性的樣本。但也不能就這樣把盛行使用者放回來,因為他們早就度過了風險最高的起始期。PNU 的解法:別拿長期用 A 的人去比剛開始用 B 的人,而是把每位盛行 A 使用者,配到一位「已經用了一樣久」的對照組使用者,再用傾向分數(依各種特徵推估「會用 A」的機率,且這機率也隨距起始時間而變)把其他差異拉平。這樣既留住盛行使用者,資料更多、代表性更好,又不會產生「拿長期使用者去比剛起始者」的偏誤。出自 Suissa, Moodie & Dell'Aniello 2017。

易感者耗竭 depletion of susceptibles

「易感」就是容易出事的意思。最可能出事的人,往往很早就出事、然後退出了,他們停藥、換藥,或離開研究。所以當你去看「已經用 A 很久」的人,看到的其實是幸運的存活者:那些沒出狀況的人。他們看起來低風險,但只是因為高風險的人早就不在了,易感的人被「耗竭」掉了。例如:受不了 A 的人,頭幾個月就停藥了;還留在研究裡的長期 A 使用者,都是耐受良好、風險較低的人。陷阱在於:拿這些存活者去比剛開始用 B 的人,A 會顯得比實際更安全,於是你低估了它的危害(或高估了它的好處)。

時間條件配對 time-conditional matching

這是 PNU 真正動手做的事。「距起始時間」是指一個人已經用了多久。危險在於:拿「已經用 A 兩年」的人去比「上週才開始用 B」的人,用 A 的那位早就度過了危險的起始期,這比較不公平。時間條件配對的意思是:永遠只比較「距起始時間相同」的 A 與對照組使用者,把兩人「治療進程中的同一個時點」對齊。同時用一個會隨用藥時長改變的傾向分數,把那一刻的其他特徵拉平,讓「起始後先高、之後衰減」的危險窗對齊。它唯一的前提是:要知道每位盛行使用者真正的治療起始日,才能判斷他走到治療進程的哪一步。這樣做,就能消掉耗竭偏誤,又把盛行使用者留住。

互動:未校正合併往無效值沉;PNU 穩住真值

拉動滑桿改變易感者耗竭的強度。未校正盛行比較(A 全部 vs B 新起始者)會隨耗竭越來越被往無效值拉; 純新使用者標竿與 PNU 都停在真值,但只有 PNU 同時留住盛行使用者。

未校正盛行(A 全部 vs B 新)
–
易感者耗竭偏誤
純新使用者
–
乾淨但樣本小
PNU(時間條件)
–
應緊貼真值 1.7

資料分析:純新使用者 vs 未校正盛行 vs PNU

載入內建世代(drug=A/B、A 是否盛行使用者、距起始時間、體質、追蹤人時、是否發生事件)。工具會算純新使用者速率比 (乾淨但丟掉盛行使用者)、未校正盛行速率比(帶有耗竭偏誤),以及 PNU 時間條件估計(校正體質+距起始時間),用上盛行使用者又還原真值。

或 尚未載入資料

程式(SAS · R · Stata):盛行新使用者設計

這是可直接在可下載的 pnu_sample.csv 上完整執行的程式(欄位:pid、drug、prevalent、time_since_start、frailty、age、futime、event)。

SAS — PROC PHREG 含盛行使用者校正

/* read the sample CSV */
proc import datafile="pnu_sample.csv" out=d dbms=csv replace;
    getnames=yes;
run;

/* Cox PH: include prevalent users, adjust for time since start */
proc phreg data=d;
    class drug (ref="0");
    model futime*event(0) =
        drug prevalent time_since_start frailty age / risklimits;
    hazardratio drug;
run;

保留盛行使用者,再用 time_since_start 與 frailty 把兩組拉平。

R — survival::coxph

# read data and fit prevalent new-user Cox model
library(survival)
d <- read.csv("pnu_sample.csv")
fit <- coxph(Surv(futime, event) ~ drug + prevalent +
             time_since_start + frailty + age, data = d)
print(summary(fit))
# adjusting for time_since_start handles prevalent-user bias

模型保留盛行使用者並校正治療起始後的時間。

Stata — stset / stcox

* read data and declare survival time
import delimited "pnu_sample.csv", clear case(preserve)
stset futime, failure(event)

* Cox PH with prevalence and time-since-start adjustment
stcox i.drug prevalent time_since_start frailty age

stcox 回傳藥物效果的校正風險比。

這個 PNU 可不可信?五道體檢

核心假設大多關於研究設計(藍卡):在距起始時間條件下可交換、時間條件配對要正確、要能取得盛行使用者的治療起始史。 可檢的是 PNU 與純新使用者標竿是否一致、耗竭有多強。綠燈沒問題、黃燈要留意、紅燈有狀況、藍燈需領域判斷。

載入中…

用 AI 強化:機器學習的時間條件傾向分數

因果機器學習一次看懂:從平均效果(ATE)到個體化效果(CATE)

超越單一平均效果。傳統方法估的是一個平均處置效果(ATE)。因果機器學習更進一步,瞄準個體化/條件效果(CATE):誰受益、受益多少。Meta-learners(S-/T-/X-/DR-learner)是與模型無關(model-agnostic)的套法,把彈性 ML 放進輔助模型(結果與傾向模型),而因果識別仍靠和本頁相同的假設,無未測混淆、重疊/正性、一致性。對真實世界資料(EHR、登錄)要小心:彈性 ML 能減少模型設定錯誤的偏誤,但救不了未測混淆,而且「預測得準」不等於「因果效果」。本頁 ⑤ 的示範正是這個想法的一個具體案例,用彈性 ML 處理輔助模型,識別仍來自設計。出處:Feuerriegel 等, Nature Medicine 2024;Kaddour 等, arXiv:2206.15475;Li & Chu 主編, Springer 2023。

PNU 用時間條件傾向分數(依距起始時間+體質)把盛行使用者納回來。當「拿 A 還是 B」和距起始時間是 非線性關係(起始後的高風險期會衰減)時,只放主效應的邏輯斯 PS 設定錯誤、留下殘餘耗竭偏誤;改用 梯度提升 PS 抓到非線性,把速率比拉回真值。

文獻中的注意事項

① 時間條件設計做了關鍵的事

PNU 的去偏靠的是依距起始時間對齊的設計;ML 只是把時間條件傾向分數模型化得更彈性。沒有時間條件結構,再彈性的 PS 也修不掉耗竭。

② 距起始時間的重疊很重要

時間條件 PS 要成立,兩臂在相近的「距起始時間」都要有人(沿時間軸的重疊/正性)。若對照組沒有長期使用者可配,盛行 A 使用者就放不進去,要檢查重疊。

③ 未測的時變混淆仍在

PNU 處理量得到的時變因子(體質、距起始時間)。若有沒測到、會隨用藥時間改變、又同時影響「續用 A」與結果的因子,PNU 仍會偏,設計本身消不掉它。

陰性對照:偵測,甚至校正,未測的混淆

我們要估「接種 A 對結果 Y 的因果效應」,但有個沒測到的混淆 U(健康/就醫傾向)同時影響兩者,未校正比較就會偏。 兩個陰性對照能幫忙:一個疫苗不可能影響的陰性對照結果(NCO,W),與一個不可能影響 Y 的 陰性對照暴露(NCE,Z),兩者都仍與 U 相關。(1) 偵測:未校正估「A → W」本應為 0;若不是,就是偏誤的警訊 (Lipsitch 2010)。(2) 校正:因為 W、Z 都是 U 的代理,雙陰性對照/近端因果(P2SLS)能把 U 的效應解出來、 還原真正的 A → Y,即使 U 從未被測到(Miao 2018;regression-based PCI 2025)。

偵測(A→W 應為 0)與校正(近端因果還原真值)

看專有名詞解釋

陰性對照結果/暴露 negative-control outcome / exposure (NCO / NCE)

整個問題的根源是:有個我們從沒量到的東西,比方整體健康狀況、或一個人多願意去看病,同時左右了「誰打疫苗」和「誰出事」,所以直接比較會被汙染。陰性對照就是刻意挑來的「假靶」:真正的因果關係碰不到它,但那個藏起來的因素還是會牽動它。陰性對照結果(NCO,W)是疫苗根本不可能造成的事件,例如打疫苗之前就發生的事;陰性對照暴露(NCE,Z)則是不可能影響結果 Y 的暴露。既然這兩者真正的關聯都應該是 0,我們若還看到關聯,那一定是藏起來的混淆漏出來的,這正是我們要抓的破綻。這一對也能反過來拿去把偏誤消掉(見下一張卡)。源頭:Lipsitch, Tchetgen Tchetgen & Cohen 2010。

近端因果推論/混淆橋 proximal causal inference / confounding bridge

偵測偏誤是一回事,這張卡是真的把偏誤拿掉。兩個陰性對照都是那個未測混淆的「影子」,所以只要觀察它們怎麼一起變動,就能把藏起來的因素當時在做什麼反推回來、再扣掉,即使我們從沒量到它。把這些影子和混淆連回去的那套換算關係,就叫混淆橋;嚴謹版是在一個「代理帶的資訊夠豐富」的技術條件下,解一道方程把它求出來(Miao 2018;Tchetgen Tchetgen 等)。當一切是線性時,有個簡單的兩步驟做法 P2SLS:第一步:W ~ A+Z+X → Ŵ(先預測陰性對照結果),再第二步:Y ~ A+Ŵ+X;第二步裡 A 的係數,就是去偏後的因果效應。重點是:它不只是標出未測混淆,而是把它校正掉。

實證校準 empirical calibration

拿一大批陰性對照,也就是我們有把握「真值就是 0」的關係,把研究的方法套到它們全部上面。在一個嚴謹的研究裡,這些結果都應該落在 0 附近;如果它們反而系統性地偏向某個方向,這個漂移量就量出了研究內建的偏誤。接著我們用這個量到的漂移,去校準真正結果的 p 值與信賴區間:把它們放寬、平移,以反映陰性對照揭露出來的偏誤。為什麼重要:一般的 p 值假裝唯一的誤差只是抽樣的運氣,但真實研究還帶有系統誤差;用這些已知為 0 的對照來校準,偽陽性率才會準確。源頭:Schuemie 等 2014(p 值)、2018(信賴區間)。見 ⑤。

互動:偵測訊號隨混淆放大,而近端因果穩在真值

拉動滑桿改變未測混淆 U 的強度。未校正 A→Y 被推得離真值越來越遠;同時陰性對照 A→W(本應為 0)也跟著放大, 這就是偵測訊號。用同一對陰性對照的近端因果 P2SLS,不管混淆多強都穩在真值。

未校正 A→Y
–
被未測 U 偏
偵測 A→W(應 0)
–
偏誤訊號
近端 P2SLS
–
應緊貼真值 1.0

資料分析:用 A→W 偵測、用近端 P2SLS 校正

載入內建世代(治療 A、結果 Y、共變項 X、陰性對照結果 W、陰性對照暴露 Z;混淆 U 未測)。工具會給出未校正估計、 A→W 偵測訊號,以及還原真值的近端 P2SLS 估計(附自助信賴區間)。

或 尚未載入資料

程式(SAS · R · Stata):陰性對照/近端因果推論

出處 — R 使用 AER 套件的 ivreg(),呼叫方式同 AER 官方手冊(?ivreg / AER vignette)的兩階段最小平方示範;Stata 為 ivregress 2sls 官方手冊語法(近端因果的 P2SLS 即此兩階段形式)。

這是可直接在可下載的 nc_sample.csv 上完整執行的程式(欄位:pid, A, Y, X, W, Z;Z 為陰性對照暴露、W 為陰性對照結果、X 為已測共變項)。

SAS — 兩階段橋估計

/* import the sample */
proc import datafile="nc_sample.csv" out=d dbms=csv replace;
    getnames=yes;
run;
/* stage 1: predict W from Z (instrument), A and X */
proc reg data=d;
    model W = Z A X;
    output out=s1 p=What;
run;
/* stage 2: corrected A->Y effect using fitted bridge What */
proc reg data=s1;
    model Y = A What X;
run;

第一階段以 Z 建立 W 的混淆橋;第二階段代入以得到修正後的 A 效果。

R — AER::ivreg 兩階段

# load data and package
library(AER)
d <- read.csv("nc_sample.csv")
# two-stage confounding-bridge estimation
# Z is the negative-control exposure used as an instrument for W
fit <- ivreg(Y ~ A + W + X | A + Z + X, data = d)
# corrected A -> Y effect with proximal correction
summary(fit)

ivreg() 以陰性對照暴露 Z 作為陰性對照結果 W 的工具變數,去除 A 效果的偏誤。

Stata — ivregress 2sls

* import the sample
import delimited "nc_sample.csv", clear case(preserve)
* two-stage least squares: instrument W with Z
ivregress 2sls Y A X (W = Z)
* report the corrected A -> Y coefficient
estimates table, b se

ivregress 2sls 以工具變數 Z 配適 W 的橋,得到修正後的 A 效果。

這個 NC 分析可不可信?五道體檢

核心假設大多關於陰性對照的有效性與混淆橋的存在,無法用資料檢驗(藍卡):NCO 不受暴露影響、NCE 不影響結果、 且混淆橋/完備性成立。可檢的是代理相關性(第一階段強度,類似 IV)與資料量。綠燈沒問題、黃燈要留意、紅燈有狀況、藍燈需領域判斷。

載入中…

用 AI 強化:用一批陰性對照做實證校準

因果機器學習一次看懂:從平均效果(ATE)到個體化效果(CATE)

超越單一平均效果。傳統方法估的是一個平均處置效果(ATE)。因果機器學習更進一步,瞄準個體化/條件效果(CATE):誰受益、受益多少。Meta-learners(S-/T-/X-/DR-learner)是與模型無關(model-agnostic)的套法,把彈性 ML 放進輔助模型(結果與傾向模型),而因果識別仍靠和本頁相同的假設,無未測混淆、重疊/正性、一致性。對真實世界資料(EHR、登錄)要小心:彈性 ML 能減少模型設定錯誤的偏誤,但救不了未測混淆,而且「預測得準」不等於「因果效果」。本頁 ⑤ 的示範正是這個想法的一個具體案例,用彈性 ML 處理輔助模型,識別仍來自設計。出處:Feuerriegel 等, Nature Medicine 2024;Kaddour 等, arXiv:2206.15475;Li & Chu 主編, Springer 2023。

除了單一陰性對照,用一整批已知為虛無的陰性對照,可以量出研究的系統誤差並校準統計量(Schuemie 等)。兩個里程碑: (2014,Stat Med)把陰性對照擬合成經驗虛無,校準p 值;(2018,PNAS)再加進一批陽性對照 (已知非零的真效應),讓系統誤差能隨真效應大小變化,進而校準信賴區間,這篇 PNAS 證明:未校正 95% CI 涵蓋真值的比例 只有大約一半,校準後才拉回 ~95%。(這是資料驅動的校準;ML 前沿,DANCE 自動找陰性對照、ML 近端橋函數,見下方註。)

文獻中的注意事項

① 校準是資料驅動,不是 ML 本身

實證校準只是把陰性對照的估計擬合成簡單的經驗虛無分布,很有用,但本身不是機器學習。

①b 為什麼 PNAS 2018 需要陽性對照

陰性對照只揭露真效應為 0 時的偏誤。要校準信賴區間,需要知道各種真效應大小下的偏誤,所以 PNAS 加入陽性對照,已知非零真效應,通常用「在陰性對照上以已知相對風險注入額外結果事件」合成而來。擬合出的系統誤差模型 a+b·θ(殘差 SD τ)就能讓 CI 正確地平移/加寬。b≠0 代表偏誤本身會隨真效應大小而不同。

② ML 前沿:找到並用上陰性對照

ML 用在 (a) DANCE,資料驅動地搜尋/驗證陰性對照(Kummerfeld 2024);(b) 非線性近端因果的彈性 ML 橋函數。本頁未實作。

③ 對照選錯,校準也錯

校準假設這些對照真的虛無、且和研究共享系統誤差。無效的對照(其實非虛無、或偏誤結構不同)會扭曲經驗虛無,要靠領域知識挑選。

中介分析:效果有多少是「透過中介」發生的?

其他方法問疫苗「有沒有效」;中介分析問「怎麼有效」:疫苗對感染 Y 的保護,有多少是透過提高抗體 M (間接效果 NIE),有多少走其他路徑(直接效果 NDE)?總效果拆成 TE = NDE + NIE, 並報被中介比例=NIE ÷ TE。它的識別條件比「估單一效果」嚴格得多,尤其是無未測的中介–結果混淆, 無法用資料檢驗,所以敏感度分析不可少。

中介三角:A → M → Y,外加 A → Y 直接路徑

看專有名詞解釋

總/直接/間接效果 total / direct / indirect effect

假設疫苗 A 降低你感染 Y 的機會。總效果就是一個人從沒打到有打、感染風險整體下降了多少。但這個下降有兩個來源:一部分是因為疫苗提高了抗體 M、抗體把病毒擋掉;另一部分走其他路徑(例如訓練其他免疫細胞)。間接效果是透過抗體的那一份,想像你幫某人打了疫苗,但只讓他的抗體照疫苗會推的方向變動,再問光是這樣 Y 變了多少(正式寫成 NIE:在 A=1 下,把 M 從沒打時的水準 M(0) 搬到打了之後的水準 M(1))。直接效果是其餘全部,把抗體凍在沒打時的水準、只把疫苗打開(NDE)。兩者相加:TE = NDE + NIE。這之所以重要,是它告訴你機制:若保護大半是間接的,針對抗體加強(如追加劑)會有用;若大半是直接的,抗體就不是那根槓桿。

被中介比例/控制直接效果 proportion mediated / controlled direct effect (CDE)

被中介比例只回答一句話:「疫苗的整體好處裡,有幾成是走抗體的?」,就是間接除以總效果,NIE ÷ TE。若是 0.6,代表六成保護走的是抗體那條路。控制直接效果(CDE)是相關但更直接的概念:不讓抗體照自然水準走,而是把每個人的抗體強行固定在某個選定值 m,再問疫苗本身還做了什麼,就像問「如果我硬把大家的抗體調到同一水準,光打針還有用嗎?」。它需要的「信任跳躍」比 NDE/NIE 少(不必想像「同時存在兩個平行世界」那一步),所以當那些假設站不穩時很好用。一個陷阱:若疫苗讓抗體更賣力(暴露–中介交互),偷懶地「把 Y 同時對 A 和 M 跑迴歸」算出的直接效果會錯,得改用明確容許這種交互的分解(VanderWeele)。

序列可忽略性/敏感度分析 sequential ignorability / sensitivity analysis

要把效果拆成「走抗體」和「不走抗體」,需要的信任比單純量「疫苗整體有沒有效」多得多。你得相信沒有任何隱藏因素同時攪亂三組關係:疫苗–感染(A–Y)、疫苗–抗體(A–M),以及最關鍵的抗體–感染(M–Y)。最後這條的麻煩在於:就算把疫苗隨機分派的試驗做得再完美,也沒有隨機分派「誰最後抗體高」,所以某個沒測到的特質(例如整體健康)可能默默地既讓抗體高、又讓感染少,假裝出一個中介故事。這件事無法用資料檢驗,所以正確的做法是敏感度分析:問那個隱藏的抗體–感染混淆要強到什麼程度,才會把你的結論翻盤,若得靠一個大到不合理的隱藏因素才翻得動,你的發現就很穩;若一個輕微的就夠,就要小心(Imai 的 medsens 正是做這件事;見 Imai, Keele & Yamamoto;VanderWeele)。

互動:加強中介路徑,看分解如何移動

拉動滑桿改變中介路徑的強度(抗體 M 對感染 Y 的保護有多強)。強度越大,間接效果 NIE 與被中介比例上升, 而直接效果 NDE 幾乎不動。強度為 0 時,保護完全不經抗體(NIE=0)。

直接效果 NDE
–
其他路徑
間接效果 NIE
–
透過抗體 M
被中介比例
–
NIE ÷ TE

資料分析:把總效果拆成 NDE + NIE

載入內建世代(治療 A、中介 M=抗體效價、結果 Y=感染分數、共變項 X)。工具配一個中介模型與一個結果模型(含暴露–中介交互), 回報自然直接效果 NDE、自然間接效果 NIE、總效果與被中介比例,各附自助信賴區間;並顯示未校正『Y~A+M』直接效果,有交互時它會偏。

或 尚未載入資料

程式(SAS · R · Stata):因果中介分析

出處 — R 使用 mediation 套件的 mediate(),流程同 mediation 官方 vignette(Tingley 等, JSS 2014)示範的「lm 中介模型 + lm 結果模型 → mediate()」;SAS 為 PROC CAUSALMED 手冊語法、Stata 為 paramed 指令說明檔語法。

這是可直接在可下載的 med_sample.csv 上完整執行的程式(欄位:pid, A, M, Y, X)。

SAS — proc causalmed

/* import the sample */
proc import datafile="med_sample.csv" out=d dbms=csv replace;
    getnames=yes;
run;
/* causal mediation: natural direct and indirect effects */
proc causalmed data=d;
    model Y = A M X;
    mediator M = A X;
    treat A;
run;

proc causalmed 配適結果與中介模型並報告自然直接/間接效果。

R — mediation::mediate

# load data and package
library(mediation)
d <- read.csv("med_sample.csv")
# mediator and outcome models
med.fit <- lm(M ~ A + X, data = d)
out.fit <- lm(Y ~ A + M + X, data = d)
# estimate ACME (indirect) and ADE (direct)
m <- mediate(med.fit, out.fit, treat = "A", mediator = "M", sims = 1000)
summary(m)

mediate() 結合中介與結果模型,給出 ACME 與 ADE。

Stata — paramed

* import the sample (paramed is a user command: ssc install paramed)
import delimited "med_sample.csv", clear case(preserve)
* parametric causal mediation: direct and indirect effects
paramed Y, avar(A) mvar(M) cvars(X) ///
    a0(0) a1(1) m(0) yreg(linear) mreg(linear)

paramed 由處理、中介與共變項模型估計自然直接與間接效果。

這個中介分析可不可信?五道體檢

中介分析建立在序列可忽略性之上,A–Y、A–M、尤其 M–Y 都無未測混淆,外加跨世界(cross-world)的「無暴露誘發的 M–Y 混淆」條件。 這些無法用資料檢驗(藍卡),也不會因為把 A 隨機分派就成立。可檢的是:是否需要暴露–中介交互、以及資料量;另有一張敏感度分析卡。 綠燈沒問題、黃燈要留意、紅燈有狀況、藍燈需領域判斷。

載入中…

用 AI 強化:非線性中介下,用彈性 ML 估自然效果

因果機器學習一次看懂:從平均效果(ATE)到個體化效果(CATE)

超越單一平均效果。傳統方法估的是一個平均處置效果(ATE)。因果機器學習更進一步,瞄準個體化/條件效果(CATE):誰受益、受益多少。Meta-learners(S-/T-/X-/DR-learner)是與模型無關(model-agnostic)的套法,把彈性 ML 放進輔助模型(結果與傾向模型),而因果識別仍靠和本頁相同的假設,無未測混淆、重疊/正性、一致性。對真實世界資料(EHR、登錄)要小心:彈性 ML 能減少模型設定錯誤的偏誤,但救不了未測混淆,而且「預測得準」不等於「因果效果」。本頁 ⑤ 的示範正是這個想法的一個具體案例,用彈性 ML 處理輔助模型,識別仍來自設計。出處:Feuerriegel 等, Nature Medicine 2024;Kaddour 等, arXiv:2206.15475;Li & Chu 主編, Springer 2023。

抗體的保護常會飽和,超過某水準再多也幫不上,所以中介→結果是非線性的。此時線性結果模型會把 NDE/NIE 分解估偏。 改用梯度提升當結果模型、搭配 g-computation(模擬反事實的中介值)學會這條曲線,就能還原真正的自然效果。按下執行(首次會載入 scikit-learn,約 5–10 秒):

文獻中的注意事項

① ML 修的是輔助模型,不是假設

彈性 ML 讓中介/結果模型配得更好,但 NDE/NIE 的識別仍靠序列可忽略性(C1–C5)。ML 救不了未測的 M–Y 混淆。

② g-computation/模擬是引擎

自然效果是用模擬的中介值 M(0)、M(1) 預測反事實結果再平均算出,正是 Imai 等的模擬法,這裡換上彈性結果模型。

傾向分數:先把混淆平衡掉,再「拿相似的人比相似的人」

我們想估疫苗 A 對結果 Y 的因果效應,但病重/體弱的人(共變項 X 大)既較容易接種、也較容易出事,這就是適應症混淆。 直接比較接種 vs 未接種會偏。傾向分數 PS = P(A=1 | X),是「在已測共變項 X 下會接種的機率」。只要把 PS 平衡掉,用 配對、IPTW 反機率加權或重疊權重,接種與未接種兩組在 X 上就看起來一樣,比較就能還原真正的效果(Rosenbaum & Rubin 1983)。

適應症混淆:X 同時驅動治療 A 與結果 Y

看專有名詞解釋

傾向分數 propensity score

先想像我們手上只有每個人「可量到」的背景資料,年齡、病得多重、其他疾病,把它們綁成一包叫 X。傾向分數把這一整包壓成一個數字:在已知這個人的背景之下,估出他「會去接種」的機率。所以一個年老體弱的人可能拿到 0.9(很可能接種),一個年輕健康的人只有 0.2。Rosenbaum & Rubin(1983)發現一件意外好用的事:只要拿分數一樣的人來比,那一整包背景 X 在接種組與未接種組之間就會變得一樣平均,等於把很多變項壓成一維。實務上就把分數幾乎相同的接種者與未接種者配成一對,或用這個分數來加權,再比較,這樣才是「拿相似的人比相似的人」。

IPTW/重疊權重/估計目標 IPTW / overlap weights / estimand

這是用分數的三種方式,回答的問題略有不同。IPTW 給每個人一個權重,等於「拿到自己實際拿到的那種處置」機率的倒數(w = A/PS + (1−A)/(1−PS)),稀有的情況算得更重,藉此造出一個「處置不再跟背景有關」的假想母體,得到的是「全體平均」的效果(ATE)。重疊權重則把最大發言權給那些「兩邊都真有可能」、處在邊界上的人,幾乎忽略結果早已註定的人(w = A·(1−PS) + (1−A)·PS);它的權重不會無限膨脹,所以最穩定(Li, Morgan & Zaslavsky 2018)。PS 配對則替每個接種者找最接近的未接種者配對,回答的是「只在接種者身上」的效果(ATT)。同一個分數,不同做法,回答的精確問題也不同。

平衡 vs 預測/正性 balance vs prediction / positivity

一個很自然的誤會,是用分數「猜得多準」(猜中誰接種)來評斷它好不好,但這是錯的判準。你真正要的是平衡:配對或加權之後,接種組與未接種組在每一項背景變項上都該長得一樣。常用的尺是標準化平均差(SMD),大致就是兩組的差距用「標準差」當單位來量,每一項都希望壓在大約 0.1 以下。分數能多銳利地預測接種(它的 AUC)根本不重要。另一個必要條件是正性(重疊):每一種人都得至少有一點真實機會落入任一組,也就是分數要嚴格落在 0 與 1 之間。如果某個人「幾乎一定」會接種,拿他那極小的機率去當分母,IPTW 權重就會變得極大,整個答案幾乎被這一個人左右。修法:把這些極端的人截斷掉,或改用不怕這問題的重疊權重。

互動:加強混淆,看未校正漂掉、PS 卻穩住

拉動滑桿改變適應症混淆的強度(嚴重度 X 同時驅動接種與結果的力道)。強度越大,未校正(接種 vs 未接種)越來越偏離真值, 而 IPTW 與重疊權重始終鎖在真正的效果上。強度為 0 時沒有混淆,連未校正都準。

未校正差異
–
被 X 偏掉
IPTW(ATE)
–
已平衡
重疊權重
–
最穩定

資料分析:未校正 vs 迴歸校正 vs PS 配對/IPTW/重疊權重

載入內建世代(治療 A、結果 Y、共變項 X=嚴重度)。工具回報未校正差異(偏)、迴歸校正、IPTW(ATE)、重疊權重(ATO) 與 PS 配對(ATT),IPTW 附自助信賴區間;並給出平衡證據:共變項 X 的標準化平均差(SMD)加權前 vs 加權後。

或 尚未載入資料

程式(SAS · R · Stata):傾向分數分析

出處 — R 使用 MatchIt 套件的 matchit()/match.data(),流程同 MatchIt 官方 vignette(Getting Started/Estimating Effects)示範的最近鄰配對後以加權 lm 估 ATT;SAS 為 PROC PSMATCH 手冊語法、Stata 為 teffects psmatch/ipw 手冊語法。

這是可直接在可下載的 ps_sample.csv 上完整執行的程式(欄位:pid, A, Y, X)。

SAS — proc psmatch

/* import the sample */
proc import datafile="ps_sample.csv" out=d dbms=csv replace;
    getnames=yes;
run;
/* propensity-score nearest-neighbour matching */
proc psmatch data=d region=allobs;
    class A;
    psmodel A(treated='1') = X;
    match method=greedy(k=1) distance=lps;
    output out(obs=match)=m matchid=mid;
run;
/* estimate ATT on matched data */
proc reg data=m;
    model Y = A;
run;

proc psmatch 建立傾向分數並進行 1:1 配對,reg 在配對樣本上給出處置效果。

R — MatchIt + lm

# load data and package
library(MatchIt)
d <- read.csv("ps_sample.csv")
# nearest-neighbour matching on the propensity score
m <- matchit(A ~ X, data = d, method = "nearest")
md <- match.data(m)
# estimate the ATT on matched data
fit <- lm(Y ~ A, data = md, weights = weights)
summary(fit)

matchit() 依傾向分數配對處理組與對照組;對配對資料的 lm() 估計 ATT。

Stata — teffects psmatch

* import the sample
import delimited "ps_sample.csv", clear case(preserve)
* propensity-score matching estimate of the ATT
teffects psmatch (Y) (A X), atet
* alternative: inverse-probability weighting
teffects ipw (Y) (A X)

teffects psmatch 依估計傾向分數配對;teffects ipw 提供 IPW 的替代估計。

這個 PS 分析可不可信?五道體檢

傾向分數只能把有測到的共變項的混淆清掉。最關鍵的假設,無未測混淆,無法用資料檢驗(藍卡)。可以檢的是: PS 的正性/重疊、加權後的共變項平衡(SMD)、以及有效樣本數;共變項該放哪些則是設計判斷。綠燈沒問題、黃燈要留意、紅燈有狀況、藍燈需領域判斷。

載入中…

用 AI 強化:高維/機器學習傾向分數

因果機器學習一次看懂:從平均效果(ATE)到個體化效果(CATE)

超越單一平均效果。傳統方法估的是一個平均處置效果(ATE)。因果機器學習更進一步,瞄準個體化/條件效果(CATE):誰受益、受益多少。Meta-learners(S-/T-/X-/DR-learner)是與模型無關(model-agnostic)的套法,把彈性 ML 放進輔助模型(結果與傾向模型),而因果識別仍靠和本頁相同的假設,無未測混淆、重疊/正性、一致性。對真實世界資料(EHR、登錄)要小心:彈性 ML 能減少模型設定錯誤的偏誤,但救不了未測混淆,而且「預測得準」不等於「因果效果」。本頁 ⑤ 的示範正是這個想法的一個具體案例,用彈性 ML 處理輔助模型,識別仍來自設計。出處:Feuerriegel 等, Nature Medicine 2024;Kaddour 等, arXiv:2206.15475;Li & Chu 主編, Springer 2023。

當「會不會接種」和共變項是非線性(交互、門檻)的關係時,只放主效應的邏輯斯 PS 把模型設定錯了:IPTW 加權後共變項仍失衡、估計偏。 改用梯度提升估 PS(高維 PS/hdPS 的精神,Schneeweiss 等 2009)把非線性學對,加權後平衡更好、ATE 回到真值。切記:PS 的標準是平衡,不是預測準度。按下執行(首次會載入 scikit-learn,約 5–10 秒):

文獻中的注意事項

① ML 讓 PS 更彈性,不會讓假設變鬆

梯度提升/高維 PS 配出更豐富的治療模型,但識別仍靠無未測混淆+正性。ML 救不了未測的混淆。

② 標準是平衡,不是 AUC

預測準度高的 PS 仍可能讓共變項失衡;永遠檢查加權後的 SMD,配到平衡為止(Brookhart;Westreich)。

③ 比起設定良好的邏輯斯 PS,增益常常不大

當真實傾向大致線性時,設定良好的邏輯斯 PS 很難被超越;ML 主要在關係非線性/高階時才划算(就像本頁示範)。一項長期失業計畫評估顯示,用 ML 估的傾向分數相對於精心建好的邏輯斯模型,只小幅改善配對(Goller、Lechner、Moczall & Wolff, Labour Economics 2020)。別反射性地用 ML,當設計(交互、門檻、共變項眾多)需要彈性時再用。

④ 拿試驗當標準、照報告指引走

一項把 PS 用多種 ML 估出、再和隨機試驗對答案的基準研究得到同一課:把共變項平衡得最好的方法(而非把治療預測得最準的)才還原試驗結果(Wang、Rosman & Lu 2025)。一篇 ML-PS 系統性回顧再補上報告指引:事先指定估計目標、共變項、平衡指標與截斷並如實報告,否則彈性 ML 很容易讓你「挑模型」(Leite 等, Psychological Methods 2025)。在大型健保理賠資料上,super learner/高維 PS 就是這個想法務實的做法(Ju,師承 van der Laan;Fan、Beemer、Yan & Levine)。

聚焦:高維傾向分數(hdPS)演算法

hdPS 在做什麼,讓理賠資料自己挑代理變數(Schneeweiss 等 2009)

行政理賠藏著像衰弱、疾病嚴重度這類未測混淆,但它們在數百個診斷、處置與藥物代碼裡留下指紋。與其猜要校正哪些,hdPS 是一個資料自適應的演算法:從那些代碼建出一大池經驗代理共變項,挑出最可能降低混淆的那些,再放進傾向分數。

  1. 選資料維度,例如住院診斷、門診診斷、處置、給藥(每一類代碼是一個「維度」)。
  2. 產生候選共變項,每個維度保留最常見的代碼,再依出現頻次把每個代碼變成代理(基線窗內 ≥1 次/≥偶發/≥頻繁)。
  3. 依潛在偏誤排序,用乘法(Bross)偏誤公式,依每個候選同時與暴露和結果的關聯強弱排名,也就是最可能左右估計的代理。
  4. 選前 k 名(常見約 200–500 個)加進研究者指定的共變項,再照常配 PS、加權/配對。

它是代理策略、不是魔法:hdPS 靠未測因子的已測代理降低混淆,但無法消除「在代碼裡沒留下任何痕跡」的混淆。事先把演算法設定(維度、代碼數、k)寫清楚以維持可重現,並在代理-結果關係非線性時搭配 ML/super learner。

動手做:實作教學與軟體

R,Ehsan Karim 的逐步 hdPS 工作坊把整個演算法走過一遍(含 ML/TMLE 延伸):ehsanx.github.io/hdPSw;另可參考 autoCovariateSelection 流程與經典的 pharmacoepi(Java)工具箱。Stata,hdps 命令套件(Tazare、Smeeth、Evans、Douglas & Williamson, Stata Journal 2023)會評估代碼盛行率、產生 hdPS 共變項、做變數選擇並把選出的代理畫出來。

TMLE 與雙重穩健:兩個模型、兩次機會

要估疫苗對結果 Y 的效果,得校正嚴重度 X 的混淆。兩個模型能幫忙:結果迴歸 Q(A,X)=E[Y|A,X](g-computation 用它)與 傾向分數 PS=P(A=1|X)(IPTW 用它)。只用其中一個,模型設錯就會偏。增廣反機率加權(AIPW)把兩者合起來、雙重穩健, 其一對就不偏。TMLE 在 g-computation 插入式估計上,再做一步目標化(targeting)微調(用「聰明共變項」擾動), 得到雙重穩健、半參數有效率、且邊界安全的估計(van der Laan & Rubin 2006;Luque-Fernandez 等 2018)。

適應症混淆:X 同時驅動治療 A 與結果 Y(且為非線性)

看專有名詞解釋

雙重穩健/AIPW double robustness / augmented IPW

要消掉嚴重度造成的偏誤,你有兩條路:一是模型化結果,預測每個人若有用藥、若沒用藥各自的 Y;二是模型化「誰會被治療」,也就是傾向分數(給定嚴重度,拿到藥的機率)。只挑一條、又把形狀猜錯,答案就歪。AIPW 把兩條一起用,於是你有兩次機會:先用結果模型算出答案,再加上一個由傾向分數驅動的修正項,把殘留的誤差擦乾淨。妙處(稱為雙重穩健)在於,兩個模型只要其一對,估計就不偏,另一個錯也沒關係。寫成一行:AIPW = mean[ (Q(1,X)−Q(0,X)) + A/PS·(Y−Q(1,X)) − (1−A)/(1−PS)·(Y−Q(0,X)) ],後面那兩塊就是修正項。

TMLE/targeting targeted maximum likelihood

先做出一個初步答案:配一個結果模型,預測每個人「有治療」與「沒治療」的結果,平均其差(這就是 g-computation 的插入式估計)。但那個模型是為了「把 Y 整體預測好」而調的,不是為了「準確抓到治療效果」,所以 TMLE 朝著「讓效果估得更準」的方向,只輕推一步,用的是一個從傾向分數削出來的「clever covariate(聰明共變項)」。這一推的幅度只是一個數字 ε,靠把(縮放後的)結果對這個聰明共變項做一個小小的邏輯斯迴歸求得。推完之後,估計變成雙重穩健(兩個模型其一對就準)、把資料能給的精度榨到最高,而且因為它仍是「從模型代入算出來」的,永遠不會跑出合理範圍(例如機率超過 1)(van der Laan & Rubin 2006)。

Super Learner/交叉擬合 Super Learner / cross-fitting

整套方法靠兩個輔助模型(結果模型與傾向模型),而你幾乎不可能事先知道哪個形狀才對。Super Learner 乾脆不用猜:它不押單一模型,而是同時試很多種,直線、樹、樣條、梯度提升,再用交叉驗證把它們調配成「預測最準」的組合,於是「至少一個抓到真相」的機率大幅提高。但有個陷阱:彈性很大的學習器會偷偷把「等下要拿來評分的那幾筆資料」背起來,把假訊號洩進效果裡。交叉擬合就是解法:每個人的輔助量,一律用「別人」訓練出的模型來預測(樣本外),絕不用他自己,這樣彈性幫得上忙,又不會汙染最後的估計。

互動:加強混淆,看未校正漂掉、雙重穩健卻穩住

拉動滑桿改變混淆強度(嚴重度 X 同時驅動治療與非線性結果的力道)。未校正越來越偏離真值,而 AIPW 與 TMLE 始終鎖在真正的效果上。為 0 時沒有混淆,連未校正都準。

未校正差異
–
被 X 偏掉
AIPW(雙重穩健)
–
其一對就不偏
TMLE(目標化)
–
穩健+有效率

資料分析:未校正 vs g-computation vs IPTW vs AIPW vs TMLE

載入內建世代(治療 A、結果 Y、共變項 X=嚴重度,X 對 Y 為非線性)。工具回報未校正差異(偏)、g-computation(只用結果模型)、 IPTW(只用傾向分數)、雙重穩健 AIPW、與 TMLE(附影響曲線 95% CI),即使單一模型可能錯,雙重穩健估計仍還原真值。

或 尚未載入資料

程式(SAS · R · Stata):目標式最大概似估計(TMLE)

出處 — R 使用 CRAN tmle 套件的 tmle(Y, A, W) 標準呼叫(見 tmle 套件參考手冊/vignette),Stata 為 eltmle 套件說明檔的標準語法;SAS 段落為依 TMLE 步驟自行編寫。

這是可直接在可下載的 tmle_sample.csv 上完整執行的程式(欄位:pid, A, Y, X)。

SAS — 聰明共變項 TMLE 步驟

/* SAS has no native TMLE proc: do the initial + clever-covariate fits */
proc import datafile="tmle_sample.csv" out=d dbms=csv replace;
    getnames=yes;
run;
/* propensity score model */
proc logistic data=d noprint;
    model A(event='1') = X;
    output out=ps p=g1;
run;
/* initial outcome model and predictions under A=0/1 */
proc logistic data=ps noprint;
    model Y(event='1') = A X;
    output out=q p=qa;
run;
/* clever covariate H = A/g - (1-A)/(1-g) feeds the targeting step */
data q2; set q; H = A/g1 - (1-A)/(1-g1); run;
proc means data=q2 mean; var qa; run;

羅吉斯傾向分數與結果模型加上聰明共變項 H,是 SAS 中 TMLE 的組成元件。

R — tmle 套件

# load data and package
library(tmle)
d <- read.csv("tmle_sample.csv")
# targeted MLE of the ATE
fit <- tmle(Y = d$Y, A = d$A, W = data.frame(X = d$X))
# print the targeted ATE estimate (psi)
print(fit$estimates$ATE)

tmle() 以資料自適應的輔助模型對 ATE 做目標化;psi 即修正後的估計。

Stata — eltmle

* import the sample (eltmle is a user package: ssc install eltmle)
import delimited "tmle_sample.csv", clear case(preserve)
* targeted maximum likelihood estimate of the ATE
eltmle Y A X, tmle

eltmle 以集成干擾學習器透過 TMLE 估計 ATE。

這個 TMLE 可不可信?五道體檢

雙重穩健只防模型設定錯,不防未測混淆。最關鍵的假設「無未測混淆」不可檢(藍),一致性與「至少一個模型對」也是。 可以檢的是:正性/重疊、與資料量。綠燈沒問題、黃燈要留意、紅燈有狀況、藍燈需領域判斷。

載入中…

用 AI 強化:交叉擬合 AIPW+梯度提升輔助模型(Super Learner 精神)

因果機器學習一次看懂:從平均效果(ATE)到個體化效果(CATE)

超越單一平均效果。傳統方法估一個平均處置效果(ATE)。因果機器學習更進一步,瞄準個體化/條件效果(CATE)。Meta-learners(S-/T-/X-/DR-learner)把彈性 ML 放進輔助模型,而因果識別仍靠相同假設,無未測混淆、重疊、一致性。TMLE/AIPW 搭 Super Learner 正是這個想法的雙重穩健經典實例。出處:Feuerriegel 等, Nature Medicine 2024;van der Laan & Rose 2011。

當結果和傾向都對共變項非線性時,只配一個線性模型(線性 g-computation)會偏。用梯度提升當兩個輔助模型、做交叉擬合的 AIPW,就能把非線性學對、ATE 回到真值。按下執行(首次會載入 scikit-learn,約 5–10 秒):

文獻中的注意事項

① ML 配輔助模型,識別不變

Super Learner 讓 Q 與 PS 更彈性,但 TMLE/AIPW 的識別仍只在無未測混淆+正性下成立。ML 救不了隱藏的混淆。

② 交叉擬合是安全帶

把輔助量做樣本外預測,移除彈性 ML 否則會洩進效果的過度配適偏誤,有效推論的必要條件(Chernozhukov 等;van der Laan & Rose)。

G-methods:當治療與混淆「隨時間互相回饋」

一種藥分兩期服用(A₀、A₁)。中間有個時變混淆 Lₜ(疾病活動度):它影響「當下是否用藥」(所以是混淆), 但過去用藥又會改變它(所以也是中介),而且它影響結果。這種治療↔混淆回饋讓標準迴歸兩頭都錯: 不校正 Lₜ→被混淆;校正 Lₜ→擋掉 A→L→Y 的效果又開啟對撞偏誤。只有 g-methods 能做對:參數 g-formula (建 L、Y 模型,模擬策略再標準化)、IPTW 邊際結構模型(用反機率加權、去掉指向 Aₜ 的箭頭)、與 g-estimation(Robins, Hernán & Brumback 2000;Naimi, Cole & Kennedy 2017)。

治療↔混淆回饋:A₀ → L₁ →(A₁ 與 Y),且 L 混淆每一期治療

看專有名詞解釋

時變混淆/治療-混淆回饋 time-varying confounding / treatment-confounder feedback

想像在兩輪治療之間量到一個指標,例如「疾病活動度」(叫它 Lₜ)。它同時扮演三個角色:它決定下一輪誰拿到藥(病重的人較常被治療)、它本身又被前一劑藥改變(藥讓你變好或變壞)、而且它影響最後結果。麻煩就在這「一身三職」。若你忽略它,病重又接受治療的人會讓藥看起來像沒效,這是單純的混淆。但若你照一般迴歸「把它放進模型校正」,反而做了兩件壞事:你擋掉藥的部分真效果(藥有一部分正是靠改善 Lₜ 才有用,控制 Lₜ 就抹掉這條路),又意外牽起一條假關聯(Lₜ 是兩件事的共同結果,控制它就打開了「對撞」這道假門)。所以這裡日常的直覺修法,「把混淆放進模型就好」,不管往哪邊轉都會錯,這正是要動用特殊方法的原因。

g-formula/IPTW-MSM parametric g-formula / marginal structural model

兩種能拿到「一般迴歸做不到」答案的正確做法。g-formula 是「自己蓋一台小模擬器」:先從資料學會指標 L 大致怎麼變、結果 Y 怎麼隨整段病史走,然後把世界重播兩次,「人人全程用藥」對「人人全程不用」,再平均兩邊的結果。因為你是照 L 真實的演變去模擬,所以既沒忽略它、也沒錯誤地擋掉它。IPTW-MSM 走另一條路:不去建結果模型,而是把每個人「重新加權」,讓整群人看起來像是「治療是隨機發的」。那些反著常理被分到組別的人(例如病重卻沒治療)權重就放大,倍率正是其治療機率的倒數;這一招把「L 指向治療」的箭頭刪掉。在這群重新平衡過的人身上,再配一條簡單的總結線 E[Yᵃ]=β₀+β₁·(a₀+a₁),斜率就是每多一劑的效果。同一個目標,兩種估法。

分類釐清:g-methods、MSM、IP 加權 how g-methods, MSMs & IP weighting fit together

三個老被混為一談的名詞,一次理清。g-methods 是「家族姓氏」,專門處理治療↔混淆回饋的整套工具,底下有三個兄弟:g-formula、邊際結構模型(MSM)、g-estimation。所以 MSM 是住在 g-methods 裡面,不是凌駕其上。第二個常見誤會(Shinozaki & Suzuki 2020 點出過)是把「MSM」和「IP 加權」當成同一件事,其實不是。MSM 是「目標」,那條寫明你要估什麼效果的式子,例如 E[Yᵃ] = β₀ + β₁·(a₀+a₁)。IP 加權只是達成這個目標的其中一種工具(你也可以改用模擬/標準化達到同一個 MSM)。而加權本身還需要它自己的輔助模型,「在已知過去下、被治療的機率」,那只是一個你得大致配對的輔助模型(nuisance model),不屬於因果問題本身。實務上的好處:為「效果式子」挑變數、和為「加權模型」挑變數,是兩件不同的工作,別搞混。

序列可交換 sequential exchangeability

這是整套方法賴以成立、必須先信的那一步。它說:在每一輪,只要把到目前為止所有量到的東西都納入考量,過去的治療、過去的指標,那麼「下一輪誰被治療」就近似擲銅板,也就是沒有任何隱藏因素同時偷偷左右治療與結果。它其實就是大家熟悉的「無未測混淆」按時間逐輪展開的版本。難處在於:你永遠無法用資料證明它,沒有哪個檢定能保證「你的紀錄收齊了所有要緊的東西」。你只能靠領域知識去論證它,所以它是關鍵卻不可檢的假設(④ 的體檢只能查你看得到的東西,查不到這一條)。

互動:加強回饋,看兩種未校正估計都失敗、g-methods 卻穩住

拉動滑桿改變回饋強度,過去治療把日後混淆 Lₜ 推動多少。強度越大,不校正(被混淆)與校正 Lₜ(擋掉 A→L→Y 路徑) 這兩種未校正估計往相反方向越偏越遠,而 g-formula 與 IPTW-MSM 始終跟著真正的「全程 vs 不用」效果走。為 0 時沒有回饋、大家一致。

不校正
–
被混淆
校正 Lₜ
–
擋掉效果路徑
g-formula
–
還原真值

資料分析:不校正 vs 校正 Lₜ vs g-formula vs IPTW-MSM

載入內建兩期世代(基線 L₀、治療 A₀、被 A₀ 推動的時變混淆 L₁、治療 A₁、結果 Y)。工具回報不校正估計(被混淆)、 校正 Lₜ 的迴歸(偏,L₁ 是中介+對撞),以及兩個 g-methods:參數 g-formula 與 IPTW 邊際結構模型, 它們還原「全程用藥 vs 全程不用」的策略效果。

或 尚未載入資料

程式(SAS · R · Stata):參數化 g-formula

出處 — R 使用 gfoRmula 套件的 gformula_continuous_eof(),參數結構同該套件官方 vignette/參考手冊(McGrath 等 2020 為套件說明論文);Stata 為 Daniel 等 gformula 指令說明檔的標準語法。

這是可直接在可下載的 gm_sample.csv 上完整執行的程式(欄位:pid, L0, A0, L1, A1, Y)。

SAS — glm 配適與模擬

/* import the wide-format sample */
proc import datafile="gm_sample.csv" out=d dbms=csv replace;
    getnames=yes;
run;
/* model L1 given the past */
proc reg data=d; model L1 = L0 A0; output out=fl1 p=pl1; run;
/* model Y given the full past */
proc reg data=d; model Y = L0 A0 L1 A1; store ymod; run;
/* simulate Y under always-treat (A0=A1=1) */
data sim1; set d; A0=1; A1=1; run;
proc plm restore=ymod; score data=sim1 out=y1 pred=yhat1; run;
proc means data=y1 mean; var yhat1; run;

配適 L1|過去與 Y|過去,再對模擬的全程處理族群評分,得到 g-formula 平均。

R — gfoRmula

# load data and reshape to long format
library(gfoRmula); library(data.table)
d <- read.csv("gm_sample.csv")
long <- rbind(
  data.frame(pid=d$pid, t=0, L=d$L0, A=d$A0, Y=NA),
  data.frame(pid=d$pid, t=1, L=d$L1, A=d$A1, Y=d$Y))
setDT(long)
# parametric g-formula: always-treat vs never-treat
fit <- gformula_continuous_eof(obs_data=long, id="pid", time_name="t",
  outcome_name="Y", covnames=c("L","A"),
  covtypes=c("normal","binary"),
  histories=c(lagged), histvars=list(c("L","A")),
  covparams=list(covmodels=c(L ~ lag1_A, A ~ L + lag1_A)),
  ymodel=Y ~ L + A + lag1_A + lag1_L,
  intvars=list("A","A"), interventions=list(list(c(static, rep(1,2))),
    list(c(static, rep(0,2)))), int_descript=c("always","never"))
print(fit)

gfoRmula 配適各時間變動共變項與結果,再模擬對比的介入策略。

Stata — gformula

* import the sample (gformula is a user command by Daniel et al)
import delimited "gm_sample.csv", clear case(preserve)
* parametric g-formula contrasting always vs never treated
gformula Y A1 L1 A0 L0, ///
  commands(Y:regress, L1:regress, A1:logit) ///
  equations(Y: A0 L0 A1 L1, L1: A0 L0, A1: A0 L0 L1) ///
  outcome(Y) baseline(L0 A0) ///
  base_confs(L0) time_varying_confs(L1) ///
  control(A0:1 A1:1) sim(10000)

gformula 為每個時間變動變數指定模型,並模擬所選處理方案。

這個 g-methods 分析可不可信?五道體檢

g-methods 建立在序列可交換(無未測時變混淆)之上,這一條不可檢(藍),一致性/策略定義明確也是。輔助模型要設定正確(可用 ML 改善,見 ⑤)。 可以檢的是:每個時點的正性、以及治療/未治療人數。綠燈沒問題、黃燈要留意、紅燈有狀況、藍燈需領域判斷。

載入中…

用 AI 強化:ML 輔助 g-formula(梯度提升輔助模型)

因果機器學習一次看懂:從平均效果(ATE)到個體化效果(CATE)

超越單一平均效果。傳統方法估一個平均處置效果(ATE)。因果機器學習更進一步,瞄準個體化/條件效果(CATE)。Meta-learners 把彈性 ML 放進輔助模型,而因果識別仍靠相同假設,這裡是序列可交換、正性、一致性。本頁 ⑤ 用 ML 配 g-formula 的 L 與 Y 模型。出處:Feuerriegel 等, Nature Medicine 2024;Naimi, Cole & Kennedy 2017。

當時變混淆的演變與結果隨病史呈非線性變化時,線性 g-formula 的輔助模型就配錯而有偏。用梯度提升當 Lₜ 與 Y 的模型(g-formula 裡 ML/Super Learner 的精神),把非線性學對、還原策略效果。按下執行(首次會載入 scikit-learn,約 5–10 秒):

文獻中的注意事項

① ML 配輔助模型,識別不變

彈性學習器讓 L 與 Y 模型配得更好,但 g-methods 的識別仍只在序列可交換+正性下成立。ML 救不了未測的時變混淆。

② 搭配雙重穩健/交叉擬合

把 ML 放進單一 g-formula 模型可能過度配適;穩健做法是雙重穩健的 g-method(如時變治療的 TMLE、ltmle)+交叉擬合,這樣其中一個輔助模型錯了也撐得住。

陰性檢驗設計:在「有來檢驗的人」裡估疫苗效力

我們想估疫苗對目標病原(如流感)的效力 VE。麻煩在就醫傾向:愛就醫的人既較常接種、也較常因症狀就醫而被檢驗、被發現感染。 用「一般族群」當對照的未校正病例對照研究,會因此產生系統性偏誤。陰性檢驗設計(TND)只在「有來就醫並檢驗」的人裡比:case=目標病原檢驗陽性、 control=檢驗陰性(其他病原)。因為兩組都來檢驗過,就醫傾向被條件掉,接種勝算比就給出 VE = 1 − OR(Jackson & Nelson 2013;Sullivan, Tchetgen Tchetgen & Cowling 2016)。

就醫傾向 H 同時驅動接種與被檢驗;TND 條件在「有檢驗」上

看專有名詞解釋

陰性檢驗設計/VE=1−OR test-negative design / VE = 1 − OR

我們想知道疫苗能把你得到某隻病原(例如流感)的機會降低多少。麻煩在於:愛看醫生的人,既比較可能已經接種、也比較可能在生病時真的去檢驗、被記錄到,所以單純在一般人群裡比「接種 vs 沒接種」,會把「保護力」和「誰會跑來被檢驗」攪在一起。陰性檢驗設計的做法是只看那些「已經帶著症狀來、也做了檢驗」的人。在他們之中,驗出目標病原陽性的就是 case,驗出陰性(其實是別的病)的就是 control。因為兩組都跨過了同一道「願意就醫並接受檢驗」的門檻,這個就醫習慣就不再左右比較。接著看 case 和 control 之間「有接種」的勝算差多少,這個比值就是勝算比(OR),效力就是 VE = 1 − OR。例如 OR = 0.4,代表疫苗把感染降了六成(Jackson & Nelson 2013)。

就醫傾向混淆 care-seeking (health-care-seeking) confounding

這就是整個設計專門要對付的麻煩根源。「就醫傾向」說白了就是一個人多容易跑去看醫生,而這單一習慣會同時推動兩件事:愛就醫的人原本就比較可能已經接種,也比較可能在感染時真的被檢驗、被確診。因為同一個看不見的特質同時餵養了「接種」和「被發現」,未校正的比較就可能讓疫苗看起來比實際更好或更差,即使根本沒人直接量過「就醫傾向」。陰性檢驗設計正是為了消掉它而打造:只研究那些已經就醫並做了檢驗的人,讓這個習慣在 case 與 control 之間大致拉平,就不再扭曲答案。

對照疾病中性 neutral control disease

對照組就是那些來看診、做了檢驗,結果得的是別的病、而非目標病原的人。設計要成立,這個「別的病」必須是疫苗完全碰不到的,這就是「中性」的意思。可以把它想成一把公平的量尺:它告訴你在「有來檢驗但其實沒被目標病原感染」的人裡,接種長什麼樣子。危險在於疫苗若也影響了對照疾病,例如讓那些別的感染變多變少、或變得更容易或更不容易被驗出。那麼這把量尺就彎了、對照被汙染,OR(連帶 VE)就會偏離真值。這正是 ④ 體檢要盯的事(見 ④ C2)。

互動:加強就醫傾向,看未校正 VE 下沉、TND 卻穩住

拉動滑桿改變就醫傾向混淆的強度(就醫傾向同時驅動接種與被檢驗的力道)。強度越大,未校正病例對照 VE 越來越低於真值(低估保護), 而 TND VE 始終鎖在真正的效果上。為 0 時沒有就醫傾向混淆、兩者一致。

未校正 VE
–
就醫傾向偏
TND VE
–
還原真值
真值 VE
–
目標

資料分析:未校正病例對照 vs 陰性檢驗設計

載入內建世代(接種、就醫時是否被檢驗、檢驗結果、真實的目標感染)。工具回報未校正 VE(一般族群對照,被就醫傾向偏)與 TND VE = 1 − OR(檢驗陽性 case vs 陰性 control 的接種勝算比),附 95% CI 與背後的 2×2 表。

或 尚未載入資料

程式(SAS · R · Stata):陰性檢驗設計

這是可直接在可下載的 tnd_sample.csv 上完整執行的程式(欄位:pid、vaccinated、tested、case、infected)。

SAS — proc logistic

/* read CSV */
proc import datafile="tnd_sample.csv" out=d dbms=csv replace;
    getnames=yes;
run;
/* restrict to tested; case = test-positive; VE = 1 - OR */
proc logistic data=d;
    where tested = 1;
    model case(event='1') = vaccinated;
run;

僅在受檢者中,vaccinated 的勝算比估計病例與疫苗的關聯;疫苗效力為 1 減該勝算比。

R — logistic glm

# test-negative design: restrict to tested == 1
d <- read.csv("tnd_sample.csv")
fit <- glm(case ~ vaccinated, family = binomial,
          data = subset(d, tested == 1))
or <- exp(coef(fit)["vaccinated"])
ve <- 1 - or
print(c(OR = or, VE = ve))

結果 case 為受檢者中的檢驗陽性;exp(coef) 為勝算比,1 - OR 即估計的疫苗效力。

Stata — logit if tested

* restrict to tested, report odds ratio; VE = 1 - OR
import delimited "tnd_sample.csv", clear case(preserve)
logit case vaccinated if tested == 1, or

if tested == 1 的限制落實陰性檢驗設計;or 選項報告勝算比,疫苗效力為 1 - OR。

這個 TND 可不可信?五道體檢

TND 去掉就醫傾向混淆,但仍仰賴多半屬於設計判斷的條件(藍):檢驗準確、疫苗不影響對照疾病、症狀相同下就醫無差別、症狀輪廓相似。 可以檢的是:檢驗者中有足夠的 case 與 control。綠燈沒問題、黃燈要留意、紅燈有狀況、藍燈需領域判斷。

載入中…

用 AI 強化:因果(調整式)TND+機器學習傾向分數

因果機器學習一次看懂:從平均效果(ATE)到個體化效果(CATE)

超越單一平均效果。因果機器學習瞄準個體化/條件效果(CATE)。Meta-learners 把彈性 ML 放進輔助模型,識別仍靠設計的假設。本頁 ⑤ 用 ML 傾向分數,為 TND 調整一個已測混淆。出處:Feuerriegel 等, Nature Medicine 2024;Schnitzer 2022, Epidemiology。

TND 去掉就醫傾向,但去不掉其他已測混淆(如年齡、共病)。當這種混淆對接種與感染是非線性影響時,未調整的 TND OR 仍偏。因果 TND 用傾向分數做反機率加權來調整它;PS 用梯度提升時 VE 回到真值,而主效應邏輯斯 PS 只修一半。按下執行(首次會載入 scikit-learn,約 5–10 秒):

文獻中的注意事項

① TND 去就醫傾向,不是去掉所有混淆

設計去掉的是就醫傾向混淆。其他已測混淆(年齡、共病、日曆時間)仍要調整,因果 TND(IPW/g-computation)就是在做這個(Schnitzer 2022;Rowley 等 2025)。

② 以試驗為標準驗證過

以隨機試驗為標準對照時,TND 在其假設下能良好還原 COVID-19 VE,而對已測混淆做調整很重要(Andrews 等 2025)。

處方順序對稱分析:快速篩出「處方瀑布」的訊號

有些藥物不良反應會以處方瀑布的形式出現:藥 A 引起某症狀,症狀又被藥 B 處理。若 A 真的引發 B,那麼在兩種藥都用過的人裡,「先 A 後 B」應該比「先 B 後 A」多。未校正順序比(cSR)=(先 A 後 B)÷(先 B 後 A)就抓這個,但它會被處方趨勢偏掉:若 B 的使用本來就隨日曆時間上升,B 對每個人都傾向「比較晚」出現,把 cSR 撐高成假訊號。PSSA 把這個趨勢除掉:虛無順序比(SRnull)是「只有趨勢」時 cSR 的期望值,校正順序比 aSR = cSR ÷ SRnull 在沒有瀑布時 ≈ 1、有真瀑布時才升上 1 以上(Hallas 1996)。

未校正順序比被處方趨勢撐高;SRnull 把它除掉 → aSR

看專有名詞解釋

順序比 cSR/aSR crude / adjusted sequence ratio

這個想法很直觀:如果藥 A 會引起某個副作用、而那個副作用又被藥 B 治療,那麼在兩種藥都吃過的人裡,「先 A 後 B」應該比「先 B 後 A」常見。所以你就數這兩種先後順序,把「先 A 後 B」叫 a、「先 B 後 A」叫 b,算出未校正順序比 cSR = a ÷ b。比值大於 1,代表 A 比較常排在前面,暗示 A 可能正在引發 B。但光是這樣數會被誤導,因為一種藥若這些年用得越來越多,對每個人來說它自然就傾向「比較晚」才出現。於是你把未校正比值除以「光靠這種時間趨勢就會有的比值」(虛無順序比 SRnull),得到校正比值 aSR = cSR ÷ SRnull。aSR 明顯大於 1,才是 A 可能引發 B 的真正警訊。

處方趨勢混淆 prescribing-trend confounding

這就是校正要修掉的陷阱。假設藥 B 比較新、用量年年上升,那麼對幾乎所有人來說,B 單純就傾向比較晚才開出來,於是「先 A 後 B」會堆積起來,就算 A 從來沒引發過 B 也一樣。這時原始計數是被日曆時間的趨勢推著走、而不是被真正的瀑布推動,它可以憑空造出一個假訊號。解法是先量出「光靠這個趨勢」順序會偏到什麼程度,這個數就是 SRnull,再把它除掉,讓校正比值 aSR 只剩下趨勢無法解釋的部分。舉個小例子:如果光是 B 用量上升就讓「先 A 後 B」變成 1.5 倍常見,那 SRnull = 1.5,未校正比值要超過 1.5 才算真訊號。

訊號偵測(產生假說)signal detection (hypothesis-generating)

PSSA 是篩檢、不是定論,它的工作是指出可疑方向,不是定罪。它快、而且自身對照(每個人當自己的對照,許多固定不變的背景差異就互相抵消),所以可以便宜地掃過大量藥物配對,只要順序看起來可疑就舉手示警。但舉手不等於證明因果:被標出的配對,還是得用更紮實、真正控制「誰會吃什麼藥」的研究追下去(世代研究、自身對照病例系列,或主動對照設計)。可以把 PSSA 想成煙霧偵測器,告訴你該把消防隊派去哪裡。它是 TreeScan(見 ⑤)一次只看一對的近親,後者把同一種篩檢一口氣跑遍整個結果階層(Hallas 1996)。

互動:加大瀑布,看未校正 SR 一直高、aSR 把訊號從趨勢中分出來

拉動滑桿改變真實瀑布的強度(A 實際引發 B 的頻率)。未校正 SR 從頭到尾都高,連瀑布為 0 時也是,因為光是處方趨勢就把它撐高(假訊號)。校正 SR(aSR)在沒有瀑布時落在虛無(≈1),只有真瀑布變大時才往上爬。這個落差就是重點:真正的訊號是 aSR,不是 cSR。

未校正 SR
–
趨勢撐高
SRnull(趨勢)
–
趨勢基準
校正 SR(aSR)
–
真正的訊號

資料分析:未校正 SR vs 校正 SR(aSR = cSR ÷ SRnull)

載入內建的新使用者世代(指標藥 A 與標記藥 B 的首次起始月)。工具回報未校正 SR(被處方趨勢偏)、它隱含的 SRnull、以及校正 SR aSR = cSR ÷ SRnull 附 95% CI,並判斷這對是否被標為訊號(aSR 的 CI 不含 1)。

或 尚未載入資料

程式(SAS · R · Stata):處方順序對稱分析

這是可直接在可下載的 pssa_sample.csv 上完整執行的程式(欄位:pid、t_index、t_marker、index_first)。

SAS — PROC FREQ 二項檢定

/* read data */
proc import datafile="pssa_sample.csv" out=d dbms=csv replace;
    getnames=yes;
run;

/* sequence ratio = P(index first) / P(marker first) */
proc freq data=d order=data;
    tables index_first / binomial(p=0.5) alpha=0.05;
    exact binomial;
run;
/* divide crude SR by null SR for the adjusted estimate */

PROC FREQ 給出 index-first 比例與精確二項檢定。

R — table + binom.test

# read data and count sequence order
d <- read.csv("pssa_sample.csv")
n_idx <- sum(d$index_first == 1)
n_mrk <- sum(d$index_first == 0)
sr <- n_idx / n_mrk
# crude sequence ratio and exact binomial test
cat("Crude sequence ratio =", round(sr, 3), "\n")
print(binom.test(n_idx, n_idx + n_mrk, p = 0.5))
# adjust by dividing by the null (expected) sequence ratio

未校正順序比 > 1 表示標記藥傾向出現在指標藥之後。

Stata — bitest

* read data
import delimited "pssa_sample.csv", clear case(preserve)

* exact binomial test against null probability 0.5
bitest index_first == 0.5
* sequence ratio = mean / (1 - mean) of index_first
summarize index_first

bitest 檢定不對稱;index_first 平均值可得序列比。

這個 PSSA 訊號可不可信?五道體檢

PSSA 是訊號偵測(產生假說)的方法;它的效度多半是設計判斷(藍):合理的瀑布方向、合適的時間窗、新使用者(incident)認定。可以檢的是:趨勢把 SRnull 推離 1 的程度,以及兩個方向是否都有足夠的不一致對。綠燈沒問題、黃燈要留意、紅燈有狀況、藍燈需領域判斷。

載入中…

用 AI 強化:核心篩檢沒有 ML 版本,前沿在高通量篩檢

因果機器學習一次看懂:從平均效果(ATE)到個體化效果(CATE)

超越單一平均效果。因果機器學習瞄準個體化/條件效果(CATE),用 meta-learners 把彈性 ML 放進輔助模型。PSSA 性質不同:它是自身對照的訊號篩檢、不是效果估計器,沒有讓 ML 發揮的輔助模型。這裡的前沿是高通量篩檢(TreeScan),不是 CATE。出處:Feuerriegel 等, Nature Medicine 2024;Hallas 1996;Kulldorff 等 2003。

PSSA 的估計式就是幾個計數和一個比值:cSR = a ÷ b、SRnull 來自經驗時序分布、aSR = cSR ÷ SRnull。沒有要學的模型,SRnull 本身已是趨勢的無母數(經驗 CDF)估計,沒有讓 ML 發揮的對象。與其硬掛一層假「AI」,這裡交代全貌,以及這個方法指向的真正前沿。

① 為什麼沒有 ML 版本

PSSA 的效度來自自身對照(每個人當自己的對照)與用無母數 SRnull 除掉趨勢,不是來自彈性的結果/傾向模型。把 ML 加到這個比值上,並不能處理它真正的限制(瀑布方向、時間窗、事件相依時序);那只是裝飾、不是方法。

② 真正的前沿:高通量篩檢(TreeScan)

PSSA 一次篩一對。要一次篩上千個結果又控制這麼多重複比較帶來的整體型一錯誤,領域用的是樹狀掃描統計(TreeScan),在結果階層上掃 Bernoulli 對數概似比、用蒙地卡羅排列法給 p 值。它是這個自身對照篩檢的可擴展表親;本工具箱另把它做成完整方法。

③ 謹慎推測,明確標示

推測:ML 可能在 PSSA 的周邊幫上忙,例如為 SRnull 學一個更彈性的時間趨勢,或用分類器分流「哪些被標出的配對值得做控混淆的追蹤」。這些是合理的研究方向、不是既定方法的一部分,本工具未實作。

樹狀掃描統計:一次掃整個結果階層,又不被假警報淹沒

在一次藥物暴露後,我們可能想盯著數百到數千個可能的不良反應結果,並把它們組織成階層(具體事件巢狀在身體系統底下,如 MedDRA PT→SOC)。若把每個節點分開檢定,光是多重比較就保證會有偽陽性。樹狀掃描統計(TreeScan)掃描每個節點,葉節點與父節點,用 Bernoulli 對數概似比(LLR)量「該節點的暴露比例超過基準多少」,取整棵樹的最大 LLR 當作單一檢定統計量,再用打亂暴露標籤的排列法得到 p 值。這個「最大統計量」校正一次就把所有節點的族系錯誤率控制住,於是只有真正的超額能存活(Kulldorff 等 2003)。

掃描樹的每個節點;最大 LLR +排列 p 控制族系錯誤率

看專有名詞解釋

樹狀掃描統計/最大 LLR tree-based scan statistic / max LLR

想像有成千上萬種可能的副作用,像家族樹一樣排好,具體症狀掛在比較大的身體系統底下。你想一次在每一個位置問:「暴露組在這裡的病例是不是多得異常?」對每個位置我們算一個數字,叫對數概似比(LLR):它衡量「該位置暴露組的病例比例,比碰運氣該有的多出多少」,LLR 越大,代表這個超額越令人意外。巧妙之處在於不只看單一葉節點,也看它們的父分支:一個分散在好幾個相關症狀上的弱訊號(每個單看都太小、看不出來),在共同的父節點底下就會加總起來、被看見。接著我們把整棵樹裡最大的那個 LLR 當作頭條數字,最響的那聲警報,再由下一步判斷連這一個是不是真的(Kulldorff 等 2003)。

排列法 p 值/族系錯誤率 permutation p-value / family-wise error rate

如果你檢驗了上千個位置,總有一些純粹靠運氣看起來「顯著」,買越多張彩券,越可能有一張碰巧中獎。族系錯誤率講的正是這個風險:整棵樹上出現任何一個假警報的機會。為了防它,我們模擬一個「純屬碰運氣」的世界:把暴露標籤隨機打亂(讓每個人的暴露和他的結果再無真實關聯),記下這時整棵樹靠運氣能冒出的最大 LLR;重複幾千次,就拼出「光靠運氣,警報最響能有多響」的全貌。某節點的校正後 p 值,就是它真實的 LLR 在這堆「運氣值」裡排第幾,p 越小,代表光靠運氣很難達到這麼響。因為每一輪都拿最大的運氣值來比,「我們到處都看了」這件事的校正已經內建,於是一次就把族系錯誤率守住。

訊號偵測(產生假說)signal detection (hypothesis-generating)

TreeScan 是篩檢,不是定論。它像在沙灘上掃金屬探測器,告訴你「哪裡值得挖」,哪些藥物–結果配對值得做更仔細、控制混淆的研究,但它不證明這個藥造成了該事件;被標出的超額,也可能只是因為病比較重的人本來就比較會拿到這個藥。可以把它想成 PSSA(序列對稱篩檢)的放大版表親:PSSA 一次只看一對藥物–結果,而 TreeScan 一趟就掃過整個結果階層、同時把假警報壓住。它的任務是產生待驗證的假說,而不是替你下結論。

互動:在一個節點注入真超額,看未校正掃描亂標、TreeScan 卻穩住

拉動滑桿改變那一個目標節點的訊號強度(該節點的暴露勝算乘數)。強度為 1 時到處都沒有真超額,但未校正的掃描仍會因運氣標出一兩個節點(假警報),而 TreeScan 正確地一個都不標。訊號變大時,最大 LLR 往上爬、TreeScan 的排列 p 掉到 0.05 以下,標出真節點(與其父系統),同時仍守住族系錯誤率。

最大 LLR
–
最強節點
校正後 p
–
排列 FWER
未校正標記數
–
假警報
TreeScan 標記數
–
控制 FWER

資料分析:掃描樹、把節點排名、數未校正 vs FWER 控制的標記

載入內建的「暴露 vs 對照」世代(在某一個節點藏了一個真超額)。工具掃描每個葉節點與系統節點、依 LLR 排名、給每個節點排列校正 p,並對比未校正掃描會標幾個 vs FWER 控制的 TreeScan 存活幾個。

或 尚未載入資料

程式(SAS · R · Stata):樹狀掃描統計量

這是可直接在可下載的 tscan_sample.csv 上完整執行的程式(欄位:pid, leaf, exposed)。

SAS — 以 PROC SQL 彙總計數

/* Prepare the TreeScan case/total count file per leaf; scan runs in TreeScan. */
proc import datafile="tscan_sample.csv" out=d dbms=csv replace;
    getnames=yes;
run;
proc sql;
    create table counts as
    select leaf, sum(exposed) as cases, count(*) as total
    from d group by leaf;
quit;
proc print data=counts; run;
/* Then load counts (+ a tree file) into TreeScan and run the Bernoulli model. */

PROC SQL 產生各葉節點的暴露病例數與總數;實際的樹狀掃描在 TreeScan 以 Bernoulli 模型執行。

R — 彙總並輸出計數檔

# Aggregate to per-leaf counts and write the TreeScan input file
d <- read.csv("tscan_sample.csv")
counts <- aggregate(cbind(cases = exposed, total = 1) ~ leaf, data = d, FUN = sum)
print(counts)
write.table(counts[, c("leaf", "cases", "total")],
            "treescan_counts.cas", row.names = FALSE,
            col.names = FALSE, quote = FALSE)
# Then run TreeScan (Bernoulli model) on this count file plus the tree file.

aggregate() 建立各葉節點的暴露病例數與總數並輸出 .cas 計數檔;掃描統計量本身於 TreeScan 計算。

Stata — 以 collapse 彙總

* Same per-leaf aggregation; the scan runs in TreeScan (Bernoulli model)
import delimited "tscan_sample.csv", clear case(preserve)
gen total = 1
collapse (sum) cases=exposed (sum) total, by(leaf)
list
export delimited leaf cases total using "treescan_counts.cas", ///
    novarnames delimiter(space) replace

collapse 彙總各葉節點的暴露病例數與總數並輸出計數檔;再由 TreeScan 執行樹狀掃描。

這個 TreeScan 可不可信?五道體檢

TreeScan 控制多重比較,但建立在多半屬於設計判斷的條件上(藍):有意義的結果樹、有效的排列虛無(暴露可交換、無未建模混淆)。可以檢的是:各節點基準大致為常數、被標出的節點有足夠事件、排列 p 真的過了校正門檻。綠燈沒問題、黃燈要留意、紅燈有狀況、藍燈需領域判斷。

載入中…

用 AI 強化:核心是掃描統計、不是 ML 估計器,前沿在自身對照樹-時序掃描

因果機器學習一次看懂:從平均效果(ATE)到個體化效果(CATE)

超越單一平均效果。因果機器學習瞄準個體化/條件效果(CATE),用 meta-learners 把彈性 ML 放進輔助模型。TreeScan 性質不同:它是控制多重比較的訊號篩檢、不是效果估計器。這裡的前沿是更好的虛無與自身對照掃描,加上用 ML 來分流訊號,不是 CATE。出處:Feuerriegel 等, Nature Medicine 2024;Kulldorff 等 2003;Maro 等 2014。

TreeScan 的引擎是「概似比掃描+排列 p」,沒有讓 ML 發揮的輔助模型。把黑盒掛到掃描統計上,並不能處理它真正的限制(樹是否有效、虛無是否有效、殘餘混淆)。這裡交代全貌,以及這個方法指向的真正前沿。

① 為什麼核心沒有 ML 版本

效度來自排列虛無與最大統計量校正,不是來自彈性學習器。ML 無法把錯的樹變對、把被混淆的虛無變有效;那只是裝飾、不是方法。

② 真正的前沿:自身對照的樹-時序掃描

這裡的 Bernoulli 掃描假設各節點基準為常數(C2/C4)。領域的主要進展是條件型、自身對照的樹-時序掃描(每個人當自己的對照、在危險窗上掃),把那個假設拿掉,就是 SCCS 與 PSSA 背後的自身對照想法,擴大到一棵樹上。(Kulldorff 等;Maro 等 2014, FDA Sentinel。)

③ 謹慎推測,明確標示

推測:ML 可能在 TreeScan 的周邊幫上忙,例如學一個彈性的基準/傾向來分層排列,或用分類器分流「哪些被標出的節點值得做控混淆的追蹤」。這些是合理的研究方向、不是既定方法的一部分,本工具未實作。

加權累積暴露:不是「現在有沒有用藥」,而是把最近的劑量加權加總

一個藥物對風險的作用,往往既不取決於你現在有沒有在用,也不取決於你的總累積劑量,而是取決於最近劑量的加權加總,其中越久以前的劑量算得越輕。WCE 直接從資料估出這條權重函數 w(距離用藥的時間),而不是用猜的。兩個常見的未校正選擇,其實只是「把權重設錯」的特例:只看當下用藥等於說只有此刻重要(權重是 0 處的尖峰)、等權總劑量等於說過去每一劑都一樣重(一條平的權重)。當真相在中間,最近的劑量最重要、效果隨時間衰減,這兩種未校正模型都把過去的時間權重設錯、把效果估偏;WCE 則把正確的形狀抓回來(Sylvestre & Abrahamowicz 2009)。

權重函數:最近的劑量權重最高,效果隨「距離用藥的時間」衰減

看專有名詞解釋

加權累積暴露(WCE)weighted cumulative exposure

WCE 不用一個「有沒有暴露」的標籤,而是把你最近整段用藥史壓成一個數字:把你過去用過的每一劑,各自乘上一個「看多久以前」決定的權重,再加起來。剛用的劑量貢獻完整權重;很多月前的劑量貢獻就少很多(甚至為 0)。這個加權加總才是放進風險模型的東西,所以方法能抓到「最近的用藥比很久以前的用藥更重要」,而不是假裝所有用藥都一樣。

權重函數 weight function w(τ)

權重函數是一條曲線,告訴你「τ 個月前用的那一劑,現在還貢獻多少風險」。WCE 不事先把這條曲線定死,而是用幾個平滑的小積木函數(樣條)從資料估出它的形狀,所以曲線可以是衰減、可以是延遲達峰、或任何資料支持的樣子。讀這條曲線就讀出了藥的時間歷程:例如「風險主要由最近幾個月的用藥驅動」。

時變暴露 vs 兩個未校正做法 time-varying exposure vs the two naive choices

用藥是時變的:會時開時停、時增時減。兩個常見的捷徑都處理得不好。只看當下用藥=共變項是「這個月有沒有在用藥」,丟掉所有累積、假設一停藥那一刻劑量就立刻不重要。等權總劑量=把最近所有劑量等權加起來,假設一年前的劑量和昨天的一樣重要。這兩個都只是「把 WCE 的權重硬設成錯的形狀」;若真實效果會隨時間衰減,兩者都偏。

時間窗 L exposure window L

時間窗 L 是「一劑藥往回算最多還能算幾個月」,你得在配適前先選它(這裡是 24 個月)。太短,會把仍有作用的較早劑量切掉、估偏;太長,會多加一段沒用又吵的尾巴。一個好檢查:估出的權重曲線應在窗尾衰減到接近 0;若還沒,代表窗太短(見 ④ C2)。

互動:改變「效果有多偏向最近」,看未校正模型歪掉、WCE 卻穩住

拉動滑桿改變真實效果有多集中在最近的劑量(衰減越快=只有最近幾個月重要)。一個持續用藥者的真實風險比始終固定在 2.72。當你改變形狀時,未校正的只看當下用藥模型會低估(它看不到累積)、未校正的等權總劑量模型會高估或低估(形狀錯),而 WCE 不論形狀都貼在真值上,因為它是把權重曲線估出來,而不是假設它。

WCE(HR)
–
還原真值
未校正:只看當下(HR)
–
低估
未校正:等權總劑量(HR)
–
形狀錯
真值 HR
2.72
持續用藥者

資料分析:估出權重曲線,並把效果和未校正模型比一比

載入內建世代(每人逐月的用藥史、以及事件或設限的月份)。工具會估出權重曲線 w(距離用藥的時間) 與整體效果(持續用藥者的風險比),並列出未校正的「只看當下」與「等權總劑量」模型作對比。

或 尚未載入資料

程式(SAS · R · Stata):加權累積暴露

出處 — R 使用 CRAN 的 WCE 套件,呼叫 WCE(analysis="Cox", nknots, cutoff, id/event/start/stop/expos) 與 plot(fit),寫法同 WCE 套件官方 vignette/參考手冊(Sylvestre & Abrahamowicz);SAS PROC PHREG 的 (start,stop) 與 Stata stcox, tvc() 為對應的時變 Cox 近似寫法。

這是可直接在可下載的 wce_sample.csv 上完整執行的程式(欄位:id、start、stop、event、dose)。

SAS — PROC PHREG (start,stop)

/* read counting-process long form */
proc import datafile="wce_sample.csv" out=d dbms=csv replace;
    getnames=yes;
run;

/* time-dependent Cox: current dose as the simpler WCE proxy */
proc phreg data=d;
    model (start, stop)*event(0) = dose / risklimits;
run;

(start,stop) 語法處理計數過程形式下隨時間變動的劑量。

R — WCE::WCE 與權重圖

# read data and estimate the weight function
library(WCE)
d <- read.csv("wce_sample.csv")
fit <- WCE(d, analysis = "Cox", nknots = 1, cutoff = 90,
           id = "id", event = "event",
           start = "start", stop = "stop",
           expos = "dose")
print(fit)
# plot the estimated weight function
plot(fit, xlab = "Time since exposure", ylab = "Weight")

WCE 估計過去劑量隨時間的權重;圖示呈現該曲線。

Stata — stcox 配 tvc

* read counting-process data and declare survival
import delimited "wce_sample.csv", clear case(preserve)
stset stop, failure(event) id(id) time0(start)

* Cox with time-varying dose effect
stcox, tvc(dose) texp(_t)

tvc() 選項讓劑量效果隨追蹤時間變動。

這個 WCE 可不可信?五道體檢

WCE 彈性地估出權重曲線,但它建立在:暴露史量得準、時間窗夠長、風險模型形式正確,以及最關鍵、不可檢驗的,沒有時變的適應症混淆。可以檢的是:曲線在窗內衰減、事件夠多。綠燈沒問題、黃燈要留意、紅燈有狀況、藍燈需領域判斷。

載入中…

用 AI 強化:WCE 本身就是彈性函數估計,前沿在處理時變混淆

因果機器學習一次看懂:從平均效果(ATE)到個體化效果(CATE)

超越單一平均效果。因果機器學習瞄準個體化/條件效果(CATE),用 meta-learners 把彈性 ML 放進輔助模型。WCE 本身就是彈性函數估計,它用樣條從資料學出權重曲線的形狀。這裡真正的前沿不是 CATE 黑盒,而是把 WCE 和處理時變混淆的方法(邊際結構 Cox/g-methods)結合。出處:Sylvestre & Abrahamowicz 2009;Hernán & Robins;Feuerriegel 等, Nature Medicine 2024。

WCE 的整個重點已經是「讓資料決定形狀」,樣條權重曲線就是那個彈性、學出來的部分。所以沒有另一個「再加 ML」的示範可掛。這裡完整交代全貌,以及這個方法指向的真正前沿。

① 彈性已經內建

權重曲線用樣條估計、可加正則化/懲罰,這就是方法的彈性學習核心。你可以換基底(B-樣條、懲罰樣條)或用交叉驗證選平滑度,但那是在調 WCE,不是加另一層 ML。

② 真正的前沿:時變混淆

WCE 最大的威脅是「用藥的增減被會惡化的病情驅動,而病情又驅動結果」(C4)。真正的進展是把加權暴露的想法與邊際結構 Cox 模型/g-methods 結合,讓 ML 去估時變的權重/傾向,就是本工具箱其他地方的自身對照與 g-method 想法。

③ 實作附註

已發表的 WCE 用 Cox 部分概似+B-樣條(Sylvestre & Abrahamowicz 2009;R 的 WCE 套件)。本工具用「與 Cox 等價的合併邏輯斯風險+平滑基底」作為瀏覽器可行的教學重建;識別想法與權重曲線的還原是一樣的。

可轉移性:把效果從「量到的地方」搬到「要用的地方」

你在一個研究(例如試驗)裡估到了治療效果,但你要用在一個長得不一樣的目標族群。如果效果會被某個特徵 X 修飾(對某些人比較有效)、而 X 在目標族群的分布不同,那研究的效果對目標來說就是錯的數字。可轉移性把研究「重新加權/標準化」成目標的效果修飾子組成。

同一個治療、兩個族群,效果要搬得動,得先校正「誰不一樣」

研究(藍)在效果修飾子 X 上偏一邊;目標(橘)在另一邊。因為效果會隨 X 變大,研究的平均效果 ≠ 目標的。合成教學資料。

可轉移性 vs 可推廣性

可推廣性(generalizability)=目標是研究族群的子集(往內縮放)。可轉移性(transportability)=目標(部分)在研究之外,不同族群、國家或年代。兩者引擎相同:把效果修飾子的差異建模,再標準化或加權。(Adamson 等 2026 ISPE 框架;Inoue & Hsu 2024;Bareinboim & Pearl。)

看專有名詞解釋

效果修飾子 effect modifier

一個會改變「治療效果大小」的變數,例如藥對年輕病人比對年長病人更有效。它和干擾因子(會讓效果偏掉)不同,也和「只改變結果水準」的變數不同。只有當效果修飾子在目標與研究的分布不同時,才需要可轉移性。

選樣反勝算加權 inverse odds of selection weighting (IOSW)

用每個研究受試者「在共變項之下,屬於目標 vs 屬於研究」的勝算當權重。這讓重新加權後的研究樣本長得像目標的共變項組成,平均效果就變成目標的。孿生做法是標準化:配出效果曲面,再對目標的共變項取平均。

互動:拉動目標的效果修飾子平均,看研究效果歪掉、轉移把它救回

研究族群在效果修飾子 X 上固定在某個平均。拖動目標的平均。研究效果(未校正)不動,它根本不知道目標,而標準化與選樣反勝算加權會跟著目標的真實效果跑。兩族群差越多,未校正的誤差越大(加權也越吃力)。

目標真值
–
我們要的答案
研究效果(未校正)
–
忽略目標
標準化
–
救回目標
選樣反勝算加權
–
救回目標

資料分析:把研究效果搬到目標

載入內建範例(一個隨機研究+一個只有共變項的目標),工具用三種方式估目標效果:研究自己的效果(未校正)、標準化(g-formula)、選樣反勝算加權。

尚未載入資料

程式(SAS · R · Stata):試驗效應的可轉移性

這是可直接在可下載的 transport_sample.csv 上完整執行的程式(欄位:pid, S, x1, x2, A, Y)。

SAS — 在 S=1 配適、對 S=0 預測

/* Fit outcome model in trial (S=1), predict on target (S=0) under A=1 and A=0 */
proc import datafile="transport_sample.csv" out=d dbms=csv replace;
    getnames=yes;
run;
data t0 t1; set d; if S=0;
    Y=.; A=1; output t1; A=0; output t0;
run;
data fitdat; set d; if S=1; ax1 = A*x1; run;
proc reg data=fitdat outest=b noprint;
    model Y = A x1 x2 ax1;
run;
data sc; set t1 t0; ax1=A*x1; run;
proc score data=sc score=b out=pred type=parms; var A x1 x2 ax1; run;
proc means data=pred mean; class A; var model1; run;
/* transported ATE = mean(pred|A=1) - mean(pred|A=0) over S=0 rows */

含 A*x1 交互作用的結果模型在試驗資料配適,對目標列在兩種處理下計分;其平均差即轉移後的 ATE。

R — lm 與 predict 標準化

# Fit outcome model in the trial, average predicted contrast over the target
d <- read.csv("transport_sample.csv")
fit <- lm(Y ~ A*x1 + x2, data = subset(d, S == 1))
tgt <- subset(d, S == 0)
p1 <- predict(fit, transform(tgt, A = 1))
p0 <- predict(fit, transform(tgt, A = 0))
ate <- mean(p1 - p0)
print(ate)

lm() 在試驗受試者上配適結果模型;對目標共變項在 A=1 與 A=0 下預測並取差值平均,即轉移後的 ATE。

Stata — regress 與 margins

* Fit on the trial (S==1), then margins over the target (S==0) sample
import delimited "transport_sample.csv", clear case(preserve)
regress Y i.A##c.x1 c.x2 if S==1
margins, dydx(A) subpop(if S==0)

regress 在試驗上配適交互作用模型;margins, dydx(A) 搭配 subpop(S==0) 將 A 的效應標準化至目標分布。

這個轉移可不可信?五道體檢

可轉移性建立在大多無法用資料檢驗的假設上(藍卡)。最關鍵的:沒有未測量、且在兩族群分布不同的效果修飾子。可以檢的是:正性(目標落在研究的共變項支持內)、以及兩族群差多遠。綠燈沒問題、黃燈要留意、紅燈有狀況、藍燈需領域判斷。

載入中…

用 AI 強化:彈性模型,以及「搬動預測模型」

因果機器學習能把兩個轉移步驟都磨利;另外還有一整條平行文獻在討論把預測模型(不只效果)跨機構搬動。

① 彈性輔助模型、雙重穩健轉移

把選樣的 logistic 模型與結果的線性模型換成梯度提升/Super Learner,放進雙重穩健的轉移估計式,這樣只要選樣或結果模型其一對,轉移就有效,也能抓到非線性的效果修飾。

② 跨機構搬動預測模型

在 A 醫院訓練的風險模型,到 B 醫院常常變差(病人組成、編碼、儀器不同)。模型可轉移性研究模型何時/如何撐得住,並用可解釋 AI 診斷偏移,例如跨機構的急性腎損傷預測(Song 等 2020, Nat Commun)與青少年自殺預測(Zang 等 2024)。這是搬動預測模型,與搬動效果是表親。

③ 機器學習救不了什麼

彈性模型磨利的是估計、絕不是識別。轉移仍然需要:兩族群間有差異的效果修飾子全部都測得到,而且在這些修飾子上有重疊(共同支持),沒有學習器能對「你沒記到的修飾子」重新加權,而且在目標族群沒有可比單位的地方,所有模型都會危險地外推。先診斷重疊;從不重疊的族群硬轉出一個有信心的數字,比承認「這個試驗搆不到他們」更糟。

量化偏誤分析(QBA):未測混淆要多強,才能推翻你的結果?

本工具箱裡每一個觀察性設計,都靠一些自己無法檢驗的假設,最重要的是沒有未測混淆,還有沒有選擇偏誤、沒有測量誤差。量化偏誤分析(QBA)不檢驗這些假設,而是把「需要多強的偏誤才會改變你的結論」量化出來。它是一整個方法家族,從一條偏誤公式、到一個摘要數字、到完整的機率式模擬,不管哪個設計算出來的效果,都能擺在它旁邊一起報。

QBA 是一個家族,E-value 只是其中一員

所有 QBA 都問同一件事:在一個合理大小的偏誤下,真實效果會落在哪裡?差別只在你要指定多少。這個方法讓你在 ② 動手試最常見的兩種決定型做法、在 ③ 用自己的結果算、並在 ⑤ 指向更完整的機率式 QBA。

① 決定型偏誤公式(陣列法,array approach)

你假設一個混淆,它在各暴露組的盛行率、與結果的關聯,一條公式就回傳校正偏誤後的估計。完全透明;輸入就是你的假設(Schneeweiss 2006)。在 ② 試試。

② 單一摘要數字(E-value)

不假設特定混淆,反過來問:任何混淆要多強(兩端都要)才能把結果解釋掉?那個最小強度就是 E-value = RR + √(RR×(RR−1))(VanderWeele & Ding 2017)。方便快速報告;在 ② 計算。

③ 機率式 QBA(蒙地卡羅)

給偏誤參數分布而不是單一值,再模擬出「校正偏誤後的估計+帶不確定性的區間」。工具如 R 的 episensr,見 ⑤ 與參考文獻。

E-value 要多大才算夠?拿它跟真實世界的混淆比

E-value 要放在「你的領域裡合理的混淆有多強」以及「你已經量到的混淆有多強」旁邊才有意義。經驗法則:拿它和你最強的已測共變項的關聯比,若一個未測混淆得比你實際看過的任何東西都更強,結果才算穩。

  • 小效果(RR ≈ 1.2–1.5) → E-value ≈ 1.7–2.4。在多數臨床/藥物流行病學情境,兩端各約 1.5 的殘留混淆很常見(如 BMI、衰弱、抽菸 ↔ 心血管病)。這種大小的效果很脆弱,普通的混淆就足以把它解釋掉。
  • 中等效果(RR ≈ 2) → E-value ≈ 3.4。此時混淆得在兩端都強到約「抽菸 ↔ 心血管病」的程度,對一個你忘了量的東西並不常見。相當穩。
  • 大效果(RR ≈ 5) → E-value ≈ 9.9。需要兩端都強到「抽菸 ↔ 肺癌」(RR ≈ 10)的未測混淆。非常難被推翻。

一個常用的工作基準(Huang 等 2022,Ann Intern Med,報出的 E-value 約 1.4–1.7):若你領域裡合理的未測混淆強度大約落在 1.5,那麼 E-value 沒有明顯高過 ~1.5 的結果,基本上等於沒有防護。也務必一併報「信賴區間端點」的 E-value,而不只是點估計,因為那才是決定結果還能不能維持統計顯著的門檻。

看專有名詞解釋

量化偏誤分析 quantitative bias analysis (QBA)

一個總稱,指「量化估計系統性誤差(混淆、選樣、錯分類)對關聯的方向、大小與不確定性」的方法,從簡單/決定型偏誤公式、到 E-value 這類摘要量、到機率式(蒙地卡羅)偏誤分析(Lash, Fox & Fink 2009)。

E-value E-value

由 VanderWeele & Ding(2017)提出:在風險比尺度上,一個未測混淆(在已測共變項之外)必須同時和暴露、結果關聯到的最小強度,才足以把觀察到的關聯完全解釋掉。源自 Ding–VanderWeele 偏誤因子 B = (RR_EU·RR_UD)/(RR_EU+RR_UD−1)。

② 互動:兩種 QBA:陣列法(array approach)與 E-value

兩個互補的「未測混淆」量化偏誤分析。A:陣列法(array approach):假設一個混淆(它的盛行率與對結果的關聯),讀出校正偏誤後的效果。B:E-value:報出「任何混淆要多強才能把結果解釋掉」。兩個都可以拉滑桿;都是決定型偏誤公式,都不需要原始資料。

A · 陣列法(array approach):假設一個未測混淆,看校正後的效果

經典的決定型 QBA(Schneeweiss 2006),採用他《Sensitivity Analysis for Confounding》Excel 的同一套記號:把表觀(觀察)RR(ARR),假設一個二元未測混淆,給它在暴露組的盛行率 PC1、未暴露組的盛行率 PC0、以及與結果的相對風險 RRCD,就能讀出校正後的 RR。拉動滑桿,看效果怎麼移動。

曲面是「在固定 ARR 與 PC0(滑桿值)下,每一組 PC1 與 RRCD 對應的校正後 RR」,與 Schneeweiss array Excel 同一個視圖;圓點是你目前的滑桿位置。可拖曳旋轉。

偏誤因子 BF = (1 + PC1(RRCD−1)) ∕ (1 + PC0(RRCD−1));校正後 RR = ARR ∕ BF,與 Schneeweiss array-approach Excel(「Array」分頁)同一條公式。混淆只有在「兩組盛行率不同(PC1 ≠ PC0)」且「與結果有關(RRCD > 1)」時才會造成偏誤。

B · E-value:混淆要多強才推翻得了?

試試看:一個假想的未測混淆

E-value = RR + √(RR×(RR−1));偏誤因子 B = (RR_EU·RR_UD)/(RR_EU+RR_UD−1)。VanderWeele & Ding(2017),Ann Intern Med。

③ 從你自己的結果算出來

E-value 不需要原始資料,只要你報告的效果與信賴區間就能算,把「點估計的 E-value」和「CI 端點的 E-value」都報出來。


程式(SAS · R · Stata):E 值敏感度分析

出處 — R 使用 EValue 套件的 evalues.RR(est, lo, hi),呼叫方式同 EValue 官方手冊/vignette(CRAN: package=EValue)。

這是可直接在可下載的 evalue_sample.csv 上完整執行的程式(欄位:outcome, rr, lo, hi)。

SAS — 封閉式 E 值公式

/* E-value formula: E = RR + sqrt(RR*(RR-1)); use 1/RR if RR<1 */
proc import datafile="evalue_sample.csv" out=d dbms=csv replace;
    getnames=yes;
run;
data d; set d;
    rr_p = rr; if rr_p < 1 then rr_p = 1/rr_p;
    e_point = rr_p + sqrt(rr_p*(rr_p-1));
    b = lo; if lo < 1 and hi < 1 then b = hi;  /* CI limit nearest 1 */
    if b > 1 then e_ci = b + sqrt(b*(b-1));
    else if b < 1 then e_ci = (1/b) + sqrt((1/b)*((1/b)-1));
    else e_ci = 1;
run;
proc print data=d; var outcome rr e_point e_ci; run;

用一個資料步驟,對點估計值和最接近虛無值的信賴區間端點套用封閉式 E-value 公式。

R — EValue::evalues.RR

# E-value for each outcome's RR and its confidence interval
library(EValue)
d <- read.csv("evalue_sample.csv")
for (i in seq_len(nrow(d))) {
    cat(as.character(d$outcome[i]), "\n")
    print(evalues.RR(est = d$rr[i], lo = d$lo[i], hi = d$hi[i]))
}

evalues.RR() 逐一處理每個結果,回傳點估計值與最接近虛無值那端信賴區間的 E-value。

Stata — 以 generate 計算封閉式

* Same closed-form E-value computed with generate
import delimited "evalue_sample.csv", clear case(preserve)
gen rr_p = cond(rr < 1, 1/rr, rr)
gen e_point = rr_p + sqrt(rr_p*(rr_p-1))
gen b = cond(lo < 1 & hi < 1, hi, lo)
gen e_ci = cond(b > 1, b + sqrt(b*(b-1)), ///
            cond(b < 1, (1/b) + sqrt((1/b)*((1/b)-1)), 1))
list outcome rr e_point e_ci

用 generate 對估計值和最接近 1 的信賴區間端點套用同一條 VanderWeele & Ding 公式。

④ QBA 管得到、管不到什麼

QBA 對「你問的那個窄問題」給出明確答案,但也只有那個問題。靠任何偏誤分析之前,先看清這些界線。

是下限,不是「沒問題」的證明

QBA 顯示結果存活,代表你建模的那種偏誤要很強才翻得動,但它不表示那種偏誤不存在。如果有一個眾所周知的強混淆沒被測到,再漂亮的數字也安慰不了人。

只涵蓋你建模的那種偏誤

每個 QBA 只針對一種偏誤,未測混淆(E-value、陣列法)、或錯分類、或選樣。針對混淆的 QBA 對測量誤差、選擇偏誤、缺失資料、或壞掉的設計(不死時間、對撞分層)一概不管,那些要各自做。

偏誤參數要你自己給

決定型 QBA(陣列法)需要混淆的盛行率與強度;機率式 QBA 需要它們的分布;E-value 則用「報出所需強度」繞開這件事。不管哪種,輸入都是假設,要在合理範圍內變動(⑥ 分頁),別只猜一個值。

⑤ 不只 E-value:更完整的偏誤分析

E-value 是最快的敏感度分析,不是唯一的。賭注大時,再搭配更豐富、常是計算式的偏誤分析。

量化偏誤分析(QBA)

不用單一摘要數字,而是替混淆的盛行率與關聯指定合理的分布,再用蒙地卡羅傳遞到「校正偏誤後的估計+區間」。工具:R 的 episensr;Lash、Fox & Fink《Applying Quantitative Bias Analysis》。

陰性對照與近端因果

一個(已知與暴露無因果的)陰性對照結果能偵測殘留混淆;近端因果還能部分校正它,是 E-value「假設式」之外、用資料驅動的互補。見本工具的 NC/PCI 方法。

其他敏感度框架

配對設計的 Rosenbaum bounds、array/偏誤公式法、臨界點分析,都是從不同角度問同一件事。E-value 最好報告;當單一數字太粗時,這些補上現實感。

⑥ 如果……?拿真實混淆來對照

E-value 要拿來和「你情境裡可能真的存在的混淆」比,才有意義。反事實問題很具體:有沒有一個真實、未測到的因子,能在兩端都達到這個強度?

如果有個已知的強混淆沒測到?

例如吸菸與許多暴露、結果的 RR ≈ 2–3。若你的 E-value 比這小、又沒校正吸菸,那結果是真的脆弱,E-value 把這件事攤開講,而不是讓你含糊帶過。

如果 E-value 很大?

E-value 若達到例如 6,代表只有「強過幾乎所有已知風險因子」的混淆才翻得動,這是強(非絕對)的安心,前提是你真的已測掉明顯的混淆,只剩罕見候選。

它永遠不會告訴你的事

E-value 量的是「所需強度」,永遠不是「是否存在」。兩個 E-value 相同的研究,可信度可能天差地遠,取決於各自把真實混淆量得多徹底。永遠要把這個數字配上「實質上還可能漏了什麼」的論證。

外部對照:單臂研究借一個對照組

有時你只能做單臂研究,每個病人都接受新治療、沒有同期對照(在罕病與腫瘤很常見,因為很難不給治療)。要估效果,你借一個外部對照:來自歷史試驗、登錄或真實世界資料的未治療病人。風險是這些外部對照和你的試驗病人不一樣(病情較重、更早的年代、編碼不同),所以直接比較會被混淆。你用標準化或傾向加權校正已測的差異,讓兩組可比。

一個治療臂+借來的對照臂,把「誰不一樣」平衡掉之後,比較才站得住

單臂試驗(青)在某個共變項平均;外部對照(琥珀)較低(如病情較重)。因為共變項會影響結果,未校正前兩臂的差 ≠ 治療效果。合成教學資料。

外部對照的定位(與法規框架)

外部/歷史對照在 ICH E10 被承認但也被警告:只有在治療效果很大、疾病自然史可預測時才可接受,因為很難排除不可比性與時代效應。現代做法用混合對照(少量同期對照+借來的外部)與貝氏動態借用(power prior、commensurate prior),當外部資料不一致時降權。與可轉移性是近親,這裡借的是一個對照臂,而非把效果搬到新族群。

看專有名詞解釋

外部/歷史對照 external / historical control

一個沒有來自同一個隨機研究的未治療對照組,取自更早的試驗、登錄或常規照護資料庫。它救了單臂設計,但用「同期隨機化的保護」換來「可比性與結果隨時間穩定」的假設。

選樣反機率加權 inverse probability of selection weighting (IPSW)

用共變項建「屬於試驗 vs 外部」的模型,再用「長得像試驗病人的勝算」加權外部對照。重新加權後的外部臂就和試驗的共變項組成相符,對比估的就是治療效果。孿生做法是標準化:把未治療的結果建模,再預測到試驗病人的共變項上。

互動:拉動外部對照「有多不一樣」,看未校正比較崩掉、校正把它救回

單臂試驗固定在某個共變項平均。拖動外部對照的平均。兩臂相同時,未校正比較沒問題;拉開後,未校正效果就離真值越來越遠,而標準化與 IPSW 仍守在真實效果上,直到兩臂幾乎不重疊,這時每個方法都吃力。

真實效果
–
我們要的答案
未校正(兩臂直接差)
–
被不平衡混淆
標準化
–
救回真值
選樣反機率加權
–
救回真值

資料分析:對外部對照臂估效果

載入內建範例(一個單臂的治療試驗+一個外部的未治療對照池),工具用三種方式估治療效果:兩臂直接差(未校正)、標準化(g-formula)、選樣反機率加權。

尚未載入資料

程式(SAS · R · Stata):外部/混合對照分析

這是可直接在可下載的 extctrl_sample.csv 上完整執行的程式(欄位:pid, treated, external, x, y)。

SAS — 合併且校正共變項的模型

/* read the sample file */
proc import datafile="extctrl_sample.csv" out=d dbms=csv replace;
    getnames=yes;
run;
/* pool concurrent + external controls; adjust for x and external source */
proc glm data=d;
    model y = treated external x / solution clparm;
run;
quit;

PROC GLM 給出頻率學派的合併治療效果;external 指標吸收來源差異。

R — lm() 合併,並說明動態借用

# read the sample file
d <- read.csv("extctrl_sample.csv")
# frequentist pooled estimate: treated effect adjusting for source + x
m <- lm(y ~ treated + external + x, data = d)
print(summary(m))
print(confint(m, "treated"))
# dynamic borrowing (power prior / commensurate prior) is done with psborrow:
# install.packages("psborrow"); library(psborrow)  # Bayesian borrowing

lm() 為簡單合併估計;psborrow 實作對外部臂的 power-prior/commensurate-prior 借用。

Stata — regress 合併模型

* read the sample file
import delimited "extctrl_sample.csv", clear case(preserve)
* pooled covariate-adjusted treatment effect
regress y treated external x
* 90% CI for the treated coefficient
regress y treated external x, level(90)

regress 重現合併的頻率學派估計;貝氏借用交由 R psborrow 處理。

這個外部對照可不可信?五道體檢

外部對照分析建立在大多無法用資料檢驗的假設上(藍卡):扣掉已測共變項後可比、無時代/來源漂移、結果定義一致。可以檢的是:正性(試驗落在外部對照的共變項支持內)、以及兩臂差多遠。綠燈沒問題、黃燈要留意、紅燈有狀況、藍燈需領域判斷。

載入中…

用 AI 強化:彈性平衡與動態借用

最大的風險是殘餘不平衡與時代漂移。機器學習與貝氏借用都想做到「外部資料只用到可信的程度」。

① 彈性、雙重穩健的平衡

把選樣的 logistic 模型與結果的線性模型換成梯度提升/Super Learner,放進雙重穩健估計式(TMLE/AIPW),只要其一對效果就有效,也能抓到兩臂間的非線性差異。高維傾向分數能從豐富的登錄資料榨出更多可比性。

② 貝氏動態借用

與其完全相信外部臂,power prior 與 commensurate prior 會從「外部資料與同期對照有多一致」學出要借多少,一致就多借、不一致就少借。這正是現代混合對照法(Schmidli 等 2014;psborrow2/RBesT),直接回應 ICH E10 對時代效應的擔憂。

③ 彈性平衡與借用仍救不了什麼

兩種工具都只作用在有測到、且可比的東西上。它們都修不了:兩個年代間未測到的預後差異(歷史對照的經典陷阱)、改變過的結果定義或評估時程、或標準照護骨幹已經不同的治療。動態借用在來源不一致時還會借得更少,所以它是把區間放寬,而不是無中生有地製造確定性。ICH E10 仍然適用:外部對照在「效果大、疾病病程可預測」時最可信。

⑥ 如果……?用反事實的語言看「工具變數 IV」

因果推論的核心是兩個反事實的對比:如果大家都接種 vs 如果大家都不接種,結果會差多少?同一個人不可能同時看到兩個世界,所以要靠設計讓「接種與不接種的人可比」。IV 並不讓全體可比,而是借一個近似隨機的推力,把效果讀在被這個推力推動的人身上。

IV 的因果結構圖(DAG),工具像一條乾淨的側門

因果結構圖(DAG)

反事實介入圖(SWIG):治療節點拆成 A∣a、結果變成反事實 Yᵃ

看不懂這兩張圖?DAG 與 SWIG 的白話導讀

因果結構圖 DAG directed acyclic graph

把它想成「誰造成誰」的地圖。每個圓圈是一個變數(治療 A、結果 Y、混淆 U、共變項…);每個箭頭是一個直接的因果方向,A→Y 讀作「A 影響 Y」。看圖三步:(1) 從治療指到結果的箭頭,就是你想估的效果;(2) 任何不經過治療、卻同時連到治療與結果的路徑(後門 back door,通常就是混淆 U)會汙染估計;(3) 一個好的設計,本質就是想辦法把這些後門擋住,校正、配對、借工具、或自身對照。圖中紅色箭頭=偏誤來源,青色箭頭=你要的效果。

反事實介入圖 SWIG single-world intervention graph

SWIG 是把 DAG「動一刀」之後的反事實圖。它把治療節點切成兩半 A∣a:左半是真實世界觀察到的治療;右邊那個小 a,是「假如我們介入、把治療設成的值」。一旦這樣設定,下游所有結果就變成反事實 Yᵃ,「如果治療被設成 a,會發生的結果」。它的好處:把可交換性畫了出來,只要把該校正的校正掉,被設定的治療就和反事實獨立(A ⫫ Yᵃ),這時資料裡的關聯才等於因果效果。一句話:DAG 告訴你「世界長怎樣」;SWIG 告訴你「假想動手介入後,效果該怎麼讀」。

① 反事實與估計目標

效果=Yᵃ⁼¹ − Yᵃ⁼⁰。IV 只在順從者(被推力推了才接種、沒推就不接種的人)身上辨識它,這是局部平均處置效果(LATE),不是全體的效果。

② 可交換性 · 正性 · 一致性

這裡不假設治療本身可交換;而是假設工具無混淆、且只透過治療影響結果(排除限制)。正性:工具確實單方向移動治療(相關性+單調性)。一致性:治療定義明確。

③ 可交換性從哪借來

來自隨機分派的推力(如隨機寄出的提醒)。因為推力近似隨機、又滿足排除限制,「推力→結果」除以「推力→治療」就是順從者的效果。

④ 對應《What If》

見第 16 章(工具變數估計)。Hernán & Robins, Causal Inference: What If (2020)。免費電子書:hsph.harvard.edu/miguel-hernan/causal-inference-book。

⑥ 如果……?用反事實的語言看「斷點回歸 RDD」

我們要的是Yᵃ⁼¹(有資格)vs Yᵃ⁼⁰(沒資格)的對比,但資格由一條尖銳規則(年齡 ≥ 65)決定。剛好在斷點,差一點點沒過的人,幾乎就是差一點點過了的人的替身:像一個小型隨機實驗。

RDD 的因果結構圖(DAG),跳階只能來自 A

因果結構圖(DAG)

反事實介入圖(SWIG):治療節點拆成 A∣a、結果變成反事實 Yᵃ

看不懂這兩張圖?DAG 與 SWIG 的白話導讀

因果結構圖 DAG directed acyclic graph

把它想成「誰造成誰」的地圖。每個圓圈是一個變數(治療 A、結果 Y、混淆 U、共變項…);每個箭頭是一個直接的因果方向,A→Y 讀作「A 影響 Y」。看圖三步:(1) 從治療指到結果的箭頭,就是你想估的效果;(2) 任何不經過治療、卻同時連到治療與結果的路徑(後門 back door,通常就是混淆 U)會汙染估計;(3) 一個好的設計,本質就是想辦法把這些後門擋住,校正、配對、借工具、或自身對照。圖中紅色箭頭=偏誤來源,青色箭頭=你要的效果。

反事實介入圖 SWIG single-world intervention graph

SWIG 是把 DAG「動一刀」之後的反事實圖。它把治療節點切成兩半 A∣a:左半是真實世界觀察到的治療;右邊那個小 a,是「假如我們介入、把治療設成的值」。一旦這樣設定,下游所有結果就變成反事實 Yᵃ,「如果治療被設成 a,會發生的結果」。它的好處:把可交換性畫了出來,只要把該校正的校正掉,被設定的治療就和反事實獨立(A ⫫ Yᵃ),這時資料裡的關聯才等於因果效果。一句話:DAG 告訴你「世界長怎樣」;SWIG 告訴你「假想動手介入後,效果該怎麼讀」。

① 反事實與估計目標

效果=斷點處的 Yᵃ⁼¹ − Yᵃ⁼⁰(局部效果)。Sharp 給斷點處所有人的資格效果;Fuzzy 給斷點處順從者的效果(把門檻當工具)。

② 可交換性 · 正性 · 一致性

可交換性:局部隨機化/連續性,斷點上下兩側其他條件幾乎相同。正性:切點兩側都有人。一致性:政策是明確的介入。

③ 可交換性從哪借來

來自門檻的任意性:沒人能精準控制自己剛好落在 65 歲的哪一側,所以在很窄的窗內,跨過門檻近似隨機。

④ 對應《What If》

RDD 是一種自然實驗,可參照「混淆」與「隨機試驗」相關章節。Hernán & Robins, Causal Inference: What If (2020)。免費電子書。

⑥ 如果……?用反事實的語言看「差異中的差異 DiD」

對受處置組,我們要的是Yᵃ⁼¹(有政策)vs 他們自己的Yᵃ⁼⁰(政策從沒發生)。第二個看不到,於是借對照組的變化來頂替「受處置組沒政策本來會有的變化」。

受處置組那個看不到的反事實

因果結構圖(DAG)

反事實介入圖(SWIG):政策節點拆成 A∣a、結果變成反事實 Yᵃ

看不懂這兩張圖?DAG 與 SWIG 的白話導讀

因果結構圖 DAG directed acyclic graph

把它想成「誰造成誰」的地圖。每個圓圈是一個變數(治療 A、結果 Y、混淆 U、共變項…);每個箭頭是一個直接的因果方向,A→Y 讀作「A 影響 Y」。看圖三步:(1) 從治療指到結果的箭頭,就是你想估的效果;(2) 任何不經過治療、卻同時連到治療與結果的路徑(後門 back door,通常就是混淆 U)會汙染估計;(3) 一個好的設計,本質就是想辦法把這些後門擋住,校正、配對、借工具、或自身對照。圖中紅色箭頭=偏誤來源,青色箭頭=你要的效果。

反事實介入圖 SWIG single-world intervention graph

SWIG 是把 DAG「動一刀」之後的反事實圖。它把治療節點切成兩半 A∣a:左半是真實世界觀察到的治療;右邊那個小 a,是「假如我們介入、把治療設成的值」。一旦這樣設定,下游所有結果就變成反事實 Yᵃ,「如果治療被設成 a,會發生的結果」。它的好處:把可交換性畫了出來,只要把該校正的校正掉,被設定的治療就和反事實獨立(A ⫫ Yᵃ),這時資料裡的關聯才等於因果效果。一句話:DAG 告訴你「世界長怎樣」;SWIG 告訴你「假想動手介入後,效果該怎麼讀」。

① 反事實與估計目標

受處置者的效果(ATT):受處置組實際的前後變化,減掉他們「沒政策本來會有的變化」。

② 可交換性 · 正性 · 一致性

可交換性以平行趨勢呈現:沒政策時兩組會一起變一樣多。正性:兩組前後期都有。一致性:政策在已知時點、定義明確。

③ 可交換性從哪借來

來自對照組的趨勢。把固定的組間差與共同時間趨勢差掉,剩下的就是政策效果,前提是趨勢真的平行(用 event-study 看前期趨勢)。

④ 對應《What If》

控制組前後比較;與「混淆」「時變治療」相關。Hernán & Robins, Causal Inference: What If (2020)。免費電子書。

⑥ 如果……?用反事實的語言看「事前事件率比 PERR」

我們想知道處置組的Yᵃ⁼¹ vs Yᵃ⁼⁰,但穩定的體質差異會混淆對比。PERR 的招式:在事前(未處置)期也算一次率比、再相除,讓時間不變、乘法型的混淆相消。

用比值的比值消掉穩定混淆

因果結構圖(DAG)

反事實介入圖(SWIG):用藥節點拆成 A∣a、結果變成反事實 Yᵃ

看不懂這兩張圖?DAG 與 SWIG 的白話導讀

因果結構圖 DAG directed acyclic graph

把它想成「誰造成誰」的地圖。每個圓圈是一個變數(治療 A、結果 Y、混淆 U、共變項…);每個箭頭是一個直接的因果方向,A→Y 讀作「A 影響 Y」。看圖三步:(1) 從治療指到結果的箭頭,就是你想估的效果;(2) 任何不經過治療、卻同時連到治療與結果的路徑(後門 back door,通常就是混淆 U)會汙染估計;(3) 一個好的設計,本質就是想辦法把這些後門擋住,校正、配對、借工具、或自身對照。圖中紅色箭頭=偏誤來源,青色箭頭=你要的效果。

反事實介入圖 SWIG single-world intervention graph

SWIG 是把 DAG「動一刀」之後的反事實圖。它把治療節點切成兩半 A∣a:左半是真實世界觀察到的治療;右邊那個小 a,是「假如我們介入、把治療設成的值」。一旦這樣設定,下游所有結果就變成反事實 Yᵃ,「如果治療被設成 a,會發生的結果」。它的好處:把可交換性畫了出來,只要把該校正的校正掉,被設定的治療就和反事實獨立(A ⫫ Yᵃ),這時資料裡的關聯才等於因果效果。一句話:DAG 告訴你「世界長怎樣」;SWIG 告訴你「假想動手介入後,效果該怎麼讀」。

① 反事實與估計目標

治療對事件率比的效果,扣掉時間不變的體質。PERR=(事後率比)÷(事前率比)。

② 可交換性 · 正性 · 一致性

只有當混淆時間不變、且乘法作用時,才達成可交換性(這樣才會相除消掉)。正性:兩組事前事後都有事件。一致性:處置期定義清楚。

③ 可交換性從哪借來

來自事前期本身:事前率比量到了穩定混淆,相除把它移掉。若混淆會隨時間變就失效(事前期捕捉不到事後的偏誤)。

④ 對應《What If》

混淆與比值型效應測度。Hernán & Robins, Causal Inference: What If (2020)。免費電子書。

⑥ 如果……?用反事實的語言看「中斷時間序列 ITS」

這裡的反事實Yᵃ⁼⁰是一條投影:把介入前的趨勢外推,當作「如果沒介入會怎樣」。效果就是實際走勢偏離這條投影的幅度。

反事實=投影出的介入前趨勢

因果結構圖(DAG)

反事實介入圖(SWIG):介入節點拆成 X∣x、結果變成反事實 Yˣ

看不懂這兩張圖?DAG 與 SWIG 的白話導讀

因果結構圖 DAG directed acyclic graph

把它想成「誰造成誰」的地圖。每個圓圈是一個變數(治療 A、結果 Y、混淆 U、共變項…);每個箭頭是一個直接的因果方向,A→Y 讀作「A 影響 Y」。看圖三步:(1) 從治療指到結果的箭頭,就是你想估的效果;(2) 任何不經過治療、卻同時連到治療與結果的路徑(後門 back door,通常就是混淆 U)會汙染估計;(3) 一個好的設計,本質就是想辦法把這些後門擋住,校正、配對、借工具、或自身對照。圖中紅色箭頭=偏誤來源,青色箭頭=你要的效果。

反事實介入圖 SWIG single-world intervention graph

SWIG 是把 DAG「動一刀」之後的反事實圖。它把治療節點切成兩半 A∣a:左半是真實世界觀察到的治療;右邊那個小 a,是「假如我們介入、把治療設成的值」。一旦這樣設定,下游所有結果就變成反事實 Yᵃ,「如果治療被設成 a,會發生的結果」。它的好處:把可交換性畫了出來,只要把該校正的校正掉,被設定的治療就和反事實獨立(A ⫫ Yᵃ),這時資料裡的關聯才等於因果效果。一句話:DAG 告訴你「世界長怎樣」;SWIG 告訴你「假想動手介入後,效果該怎麼讀」。

① 反事實與估計目標

介入點的水準跳變與斜率改變:實際值減去外推的反事實趨勢。

② 可交換性 · 正性 · 一致性

這裡的可交換性=沒有同時發生的其他事件(唯一改變的只有這個介入)。正性:前後期數夠。一致性:介入時點尖銳、明確。

③ 可交換性從哪借來

來自族群自己的過去:介入前趨勢就是反事實。若同時還有別的事改變、或趨勢形狀抓錯(自相關、季節)就失效。

④ 對應《What If》

前後比較+投影反事實;與時變治療相關。Hernán & Robins, Causal Inference: What If (2020)。免費電子書。

⑥ 如果……?用反事實的語言看「趨勢中的趨勢 TiT」

如果一個藥真的致病,那在「採用率漲得快」的層,結果也該漲得快。TiT 比較不同採用速度的層之間的結果趨勢,這套反事實邏輯能扛住部分未測混淆。

結果趨勢有沒有跟著暴露趨勢走?

因果結構圖(DAG)

反事實介入圖(SWIG):暴露節點拆成 A∣a、結果變成反事實 Yᵃ

看不懂這兩張圖?DAG 與 SWIG 的白話導讀

因果結構圖 DAG directed acyclic graph

把它想成「誰造成誰」的地圖。每個圓圈是一個變數(治療 A、結果 Y、混淆 U、共變項…);每個箭頭是一個直接的因果方向,A→Y 讀作「A 影響 Y」。看圖三步:(1) 從治療指到結果的箭頭,就是你想估的效果;(2) 任何不經過治療、卻同時連到治療與結果的路徑(後門 back door,通常就是混淆 U)會汙染估計;(3) 一個好的設計,本質就是想辦法把這些後門擋住,校正、配對、借工具、或自身對照。圖中紅色箭頭=偏誤來源,青色箭頭=你要的效果。

反事實介入圖 SWIG single-world intervention graph

SWIG 是把 DAG「動一刀」之後的反事實圖。它把治療節點切成兩半 A∣a:左半是真實世界觀察到的治療;右邊那個小 a,是「假如我們介入、把治療設成的值」。一旦這樣設定,下游所有結果就變成反事實 Yᵃ,「如果治療被設成 a,會發生的結果」。它的好處:把可交換性畫了出來,只要把該校正的校正掉,被設定的治療就和反事實獨立(A ⫫ Yᵃ),這時資料裡的關聯才等於因果效果。一句話:DAG 告訴你「世界長怎樣」;SWIG 告訴你「假想動手介入後,效果該怎麼讀」。

① 反事實與估計目標

暴露–結果的勝算比,從「快採用 vs 慢採用」層的結果上升陡度差異辨識。

② 可交換性 · 正性 · 一致性

可交換性放寬成:沒有「跨層相關趨勢」的未測混淆。正性:暴露隨時間、跨層都有變化。一致性:暴露定義明確、結果罕見。

③ 可交換性從哪借來

來自採用率的日曆時間趨勢:混淆要偏到 TiT,得剛好其趨勢跨層跟著暴露趨勢走,比「無混淆」窄得多的要求。

④ 對應《What If》

混淆與以趨勢辨識。Hernán & Robins, Causal Inference: What If (2020)。免費電子書。

⑥ 如果……?用反事實的語言看「複製-設限-加權 CCW」

問題是關於持續策略:如果大家都「早起始」(Yᵍ¹)vs 都「晚起始」(Yᵍ⁰)會怎樣?治療是隨時間展開的,直接分組會招來不死時間偏誤。CCW 在時間零點把每個人複製到兩種策略、偏離就設限、再加權,就是 g-methods 的配方。

對齊時間零點的反事實策略

因果結構圖(DAG)

反事實介入圖(SWIG):治療節點拆成 A₁∣a、結果變成反事實 Yᵍ(整個策略 ḡ)

看不懂這兩張圖?DAG 與 SWIG 的白話導讀

因果結構圖 DAG directed acyclic graph

把它想成「誰造成誰」的地圖。每個圓圈是一個變數(治療 A、結果 Y、混淆 U、共變項…);每個箭頭是一個直接的因果方向,A→Y 讀作「A 影響 Y」。看圖三步:(1) 從治療指到結果的箭頭,就是你想估的效果;(2) 任何不經過治療、卻同時連到治療與結果的路徑(後門 back door,通常就是混淆 U)會汙染估計;(3) 一個好的設計,本質就是想辦法把這些後門擋住,校正、配對、借工具、或自身對照。圖中紅色箭頭=偏誤來源,青色箭頭=你要的效果。

反事實介入圖 SWIG single-world intervention graph

SWIG 是把 DAG「動一刀」之後的反事實圖。它把治療節點切成兩半 A∣a:左半是真實世界觀察到的治療;右邊那個小 a,是「假如我們介入、把治療設成的值」。一旦這樣設定,下游所有結果就變成反事實 Yᵃ,「如果治療被設成 a,會發生的結果」。它的好處:把可交換性畫了出來,只要把該校正的校正掉,被設定的治療就和反事實獨立(A ⫫ Yᵃ),這時資料裡的關聯才等於因果效果。一句話:DAG 告訴你「世界長怎樣」;SWIG 告訴你「假想動手介入後,效果該怎麼讀」。

① 反事實與估計目標

治療策略 Yᵍ 的對比(如早 vs 晚起始;持續 vs 停藥),全體的依計畫效果。

② 可交換性 · 正性 · 一致性

序列(時變)可交換性:每個時點下一步治療無未測混淆,用反設限機率加權處理。正性:每個時點各策略都可能。一致性:策略定義明確+明確時間零點。

③ 可交換性從哪借來

來自已測的時變共變項(IPCW,g-methods),加上時間零點對齊消掉不死時間。「早 vs 晚」時兩臂最終都治療,適應症混淆大幅相消。

④ 穩定化 vs 未穩定化權重

兩者在這裡給相同點估計(邊際分子在每月加權風險中相消),差別在變異。未穩定化(分子=1,W=1/未設限機率):重建完整基線族群、對結果模型無限制,最適合 sustained 持續/停藥的加權 KM,但極端權重要截斷。穩定化(邊際分子):平均≈1、區間較窄,但分子放的基線共變項必須回到結果模型→常被迫用有母數模型。所以本工具 sustained 用未穩定化、grace/早晚啟動用穩定化。

⑤ 對應《What If》

第三部:時變治療、邊際結構模型的 IP 加權、目標試驗模擬(穩定化 vs 未穩定化權重見第 12 章)。Hernán & Robins, Causal Inference: What If (2020)。免費電子書。

⑥ 如果……?用反事實的語言看「序列試驗 Seq」

如果能把「做不到的隨機試驗」做出來呢?在每個資格時點模擬一場目標試驗:當下啟動(Yᵃ⁼¹)vs 先不啟動(Yᵃ⁼⁰),把時鐘歸零、往前追蹤、再合併。這就是目標試驗模擬,並避開不死時間偏誤。

每個資格時點一場模擬試驗,再合併

因果結構圖(DAG)

反事實介入圖(SWIG):啟動節點拆成 A∣a、結果變成反事實 Yᵃ

看不懂這兩張圖?DAG 與 SWIG 的白話導讀

因果結構圖 DAG directed acyclic graph

把它想成「誰造成誰」的地圖。每個圓圈是一個變數(治療 A、結果 Y、混淆 U、共變項…);每個箭頭是一個直接的因果方向,A→Y 讀作「A 影響 Y」。看圖三步:(1) 從治療指到結果的箭頭,就是你想估的效果;(2) 任何不經過治療、卻同時連到治療與結果的路徑(後門 back door,通常就是混淆 U)會汙染估計;(3) 一個好的設計,本質就是想辦法把這些後門擋住,校正、配對、借工具、或自身對照。圖中紅色箭頭=偏誤來源,青色箭頭=你要的效果。

反事實介入圖 SWIG single-world intervention graph

SWIG 是把 DAG「動一刀」之後的反事實圖。它把治療節點切成兩半 A∣a:左半是真實世界觀察到的治療;右邊那個小 a,是「假如我們介入、把治療設成的值」。一旦這樣設定,下游所有結果就變成反事實 Yᵃ,「如果治療被設成 a,會發生的結果」。它的好處:把可交換性畫了出來,只要把該校正的校正掉,被設定的治療就和反事實獨立(A ⫫ Yᵃ),這時資料裡的關聯才等於因果效果。一句話:DAG 告訴你「世界長怎樣」;SWIG 告訴你「假想動手介入後,效果該怎麼讀」。

① 反事實與估計目標

點治療決定(當下治療 vs 不治療)的效果,跨資格時點各試驗合併。

② 可交換性 · 正性 · 一致性

每場模擬試驗內的基線條件可交換性(用 IPTW 校正基線共變項)。正性:每個時點合格者可啟動也可不啟動。一致性:每場有明確時間零點,目標試驗模擬的核心。

③ 可交換性從哪借來

來自在每個資格時點明確模擬一場試驗並對齊時間零點。未校正的「曾 vs 從未」會偏,因為曾治療者得活到能治療,產生不死時間(immortal time);序列試驗把它移除。

④ 對應《What If》

第 22 章(目標試驗模擬)+第三部 g-methods。Hernán & Robins, Causal Inference: What If (2020)。免費電子書。

⑥ 如果……?用反事實的語言看「病例交叉與時間對照 CCTC」

不比不同的人,而是讓同一個人跟自己比:事件前的危險窗暴露(Yᵃ⁼¹)有沒有比更早的參考窗(Yᵃ⁼⁰)多?自己當對照,消掉所有不隨時間變的東西。CCTC 再扣掉暴露的日曆時間趨勢。

同一個人:危險窗 vs 參考窗

因果結構圖(DAG)

反事實介入圖(SWIG):暴露節點拆成 X∣x、結果變成反事實 Yˣ

看不懂這兩張圖?DAG 與 SWIG 的白話導讀

因果結構圖 DAG directed acyclic graph

把它想成「誰造成誰」的地圖。每個圓圈是一個變數(治療 A、結果 Y、混淆 U、共變項…);每個箭頭是一個直接的因果方向,A→Y 讀作「A 影響 Y」。看圖三步:(1) 從治療指到結果的箭頭,就是你想估的效果;(2) 任何不經過治療、卻同時連到治療與結果的路徑(後門 back door,通常就是混淆 U)會汙染估計;(3) 一個好的設計,本質就是想辦法把這些後門擋住,校正、配對、借工具、或自身對照。圖中紅色箭頭=偏誤來源,青色箭頭=你要的效果。

反事實介入圖 SWIG single-world intervention graph

SWIG 是把 DAG「動一刀」之後的反事實圖。它把治療節點切成兩半 A∣a:左半是真實世界觀察到的治療;右邊那個小 a,是「假如我們介入、把治療設成的值」。一旦這樣設定,下游所有結果就變成反事實 Yᵃ,「如果治療被設成 a,會發生的結果」。它的好處:把可交換性畫了出來,只要把該校正的校正掉,被設定的治療就和反事實獨立(A ⫫ Yᵃ),這時資料裡的關聯才等於因果效果。一句話:DAG 告訴你「世界長怎樣」;SWIG 告訴你「假想動手介入後,效果該怎麼讀」。

① 反事實與估計目標

短暫暴露對急性事件率的效果,以個人內勝算比表示(時間趨勢用對照除掉)。

② 可交換性 · 正性 · 一致性

個人內可交換性:同一人各窗除了暴露外可比(時間不變混淆相消)。正性:此人有些窗暴露、有些沒。一致性:暴露短暫、窗定義明確。

③ 可交換性從哪借來

來自自身對照(時間不變因子相消)+一條只帶暴露時間趨勢的對照序列/未來 case,CCTC 把趨勢除掉,剩下因果部分。

④ 對應《What If》

自身對照、條件可交換性;混淆與選擇偏誤章。Hernán & Robins, Causal Inference: What If (2020)。免費電子書。

⑥ 如果……?用反事實的語言看「病例對照 CC」

一個有效的病例對照,其實是對「模擬目標試驗的世代」做有效率的抽樣。反事實對比(Yᵃ⁼¹ vs Yᵃ⁼⁰)存在於來源族群;我們只在病例與一組有代表性的對照量暴露,就能省力地還原勝算比。

病例對照的因果結構圖(DAG),依結果抽樣

因果結構圖(DAG)

反事實介入圖(SWIG):暴露節點拆成 A∣a、結果變成反事實 Yᵃ

看不懂這兩張圖?DAG 與 SWIG 的白話導讀

因果結構圖 DAG directed acyclic graph

把它想成「誰造成誰」的地圖。每個圓圈是一個變數(治療 A、結果 Y、混淆 U、共變項…);每個箭頭是一個直接的因果方向,A→Y 讀作「A 影響 Y」。看圖三步:(1) 從治療指到結果的箭頭,就是你想估的效果;(2) 任何不經過治療、卻同時連到治療與結果的路徑(後門 back door,通常就是混淆 U)會汙染估計;(3) 一個好的設計,本質就是想辦法把這些後門擋住,校正、配對、借工具、或自身對照。圖中紅色箭頭=偏誤來源,青色箭頭=你要的效果。

反事實介入圖 SWIG single-world intervention graph

SWIG 是把 DAG「動一刀」之後的反事實圖。它把治療節點切成兩半 A∣a:左半是真實世界觀察到的治療;右邊那個小 a,是「假如我們介入、把治療設成的值」。一旦這樣設定,下游所有結果就變成反事實 Yᵃ,「如果治療被設成 a,會發生的結果」。它的好處:把可交換性畫了出來,只要把該校正的校正掉,被設定的治療就和反事實獨立(A ⫫ Yᵃ),這時資料裡的關聯才等於因果效果。一句話:DAG 告訴你「世界長怎樣」;SWIG 告訴你「假想動手介入後,效果該怎麼讀」。

① 反事實與估計目標

暴露勝算比(結果罕見時 ≈ 風險比),作為世代/目標試驗效果的有效率估計。

② 可交換性 · 正性 · 一致性

可交換性:已測混淆校正(無未測混淆)、對照取自來源族群。正性:兩組暴露都有變化。一致性:暴露與時間零點定義明確(新使用者、非盛行使用者)。

③ 可交換性從哪借來

來自設計良好的抽樣:對照代表產生病例的族群、兩組暴露量得一樣、混淆校正或配對,就是一個模擬目標試驗的世代,只是抽樣而已。

④ 對應《What If》

病例對照=世代抽樣;選擇偏誤章+第 22 章(目標試驗)。Hernán & Robins, Causal Inference: What If (2020)。免費電子書。

⑥ 如果……?用反事實的語言看「自身對照病例系列 SCCS」

只用發生過事件的人,每個人當自己的對照:事件比較容易落在他的暴露時段(Yᵃ⁼¹)還是非暴露時段(Yᵃ⁼⁰)?這是個人內的前後比,所有不隨時間變的因子(基因、體質、社經)都自動相消。

同一個人:暴露時段 vs 非暴露時段

因果結構圖(DAG)

反事實介入圖(SWIG):暴露時段節點拆成 X∣x、結果變成反事實 Yˣ

看不懂這兩張圖?DAG 與 SWIG 的白話導讀

因果結構圖 DAG directed acyclic graph

把它想成「誰造成誰」的地圖。每個圓圈是一個變數(治療 A、結果 Y、混淆 U、共變項…);每個箭頭是一個直接的因果方向,A→Y 讀作「A 影響 Y」。看圖三步:(1) 從治療指到結果的箭頭,就是你想估的效果;(2) 任何不經過治療、卻同時連到治療與結果的路徑(後門 back door,通常就是混淆 U)會汙染估計;(3) 一個好的設計,本質就是想辦法把這些後門擋住,校正、配對、借工具、或自身對照。圖中紅色箭頭=偏誤來源,青色箭頭=你要的效果。

反事實介入圖 SWIG single-world intervention graph

SWIG 是把 DAG「動一刀」之後的反事實圖。它把治療節點切成兩半 A∣a:左半是真實世界觀察到的治療;右邊那個小 a,是「假如我們介入、把治療設成的值」。一旦這樣設定,下游所有結果就變成反事實 Yᵃ,「如果治療被設成 a,會發生的結果」。它的好處:把可交換性畫了出來,只要把該校正的校正掉,被設定的治療就和反事實獨立(A ⫫ Yᵃ),這時資料裡的關聯才等於因果效果。一句話:DAG 告訴你「世界長怎樣」;SWIG 告訴你「假想動手介入後,效果該怎麼讀」。

① 反事實與估計目標

個人內的相對速率(IRR):暴露後危險窗的事件率相對於基線。

② 可交換性 · 正性 · 一致性

個人內對所有時間不變因子可交換(自動相消);時變因子(年齡、季節)靠切分。正性:此人有暴露也有非暴露時段。一致性:暴露短暫、且事件本身不改變日後暴露。

③ 可交換性從哪借來

來自條件在「人」上:條件 Poisson 概似消掉每個人的基線速率,所有穩定混淆依設計消失。代價:事件不可改變日後暴露。

④ 對應《What If》

自身對照設計與條件可交換性;混淆章。Hernán & Robins, Causal Inference: What If (2020)。免費電子書。

⑥ 如果……?用反事實的語言看「主動對照新使用者 ACNU」

如果大家都用藥 A(Yᵃ⁼¹)vs 都用對照藥 B(Yᵃ⁼⁰)會怎樣?拿用 A 的人和沒用藥的人比會失敗,因為嚴重度(適應症)開了後門、而沒用藥的人是更健康的族群。ACNU 靠限制在有適應症的族群(A 的新使用者 vs B 的新使用者)+校正殘留嚴重度,把可比性救回來。

適應症混淆,用主動對照擋住

因果結構圖(DAG)

反事實介入圖(SWIG):治療節點拆成 A∣a、結果變成反事實 Yᵃ

看不懂這兩張圖?DAG 與 SWIG 的白話導讀

因果結構圖 DAG directed acyclic graph

把它想成「誰造成誰」的地圖。每個圓圈是一個變數(治療 A、結果 Y、混淆 U、共變項…);每個箭頭是一個直接的因果方向,A→Y 讀作「A 影響 Y」。看圖三步:(1) 從治療指到結果的箭頭,就是你想估的效果;(2) 任何不經過治療、卻同時連到治療與結果的路徑(後門 back door,通常就是混淆 U)會汙染估計;(3) 一個好的設計,本質就是想辦法把這些後門擋住,校正、配對、借工具、或自身對照。圖中紅色箭頭=偏誤來源,青色箭頭=你要的效果。

反事實介入圖 SWIG single-world intervention graph

SWIG 是把 DAG「動一刀」之後的反事實圖。它把治療節點切成兩半 A∣a:左半是真實世界觀察到的治療;右邊那個小 a,是「假如我們介入、把治療設成的值」。一旦這樣設定,下游所有結果就變成反事實 Yᵃ,「如果治療被設成 a,會發生的結果」。它的好處:把可交換性畫了出來,只要把該校正的校正掉,被設定的治療就和反事實獨立(A ⫫ Yᵃ),這時資料裡的關聯才等於因果效果。一句話:DAG 告訴你「世界長怎樣」;SWIG 告訴你「假想動手介入後,效果該怎麼讀」。

① 反事實與估計目標

在有適應症的新使用者族群中,藥 A vs 主動對照藥 B 對結果率的效應,是相對(A vs B)效應,不是相對於「沒用藥」。

② 可交換性 · 正性 · 一致性

可交換性:限制在同適應症+校正嚴重度後,A 與 B 可比(無未測混淆)。正性:這些病人兩種藥都可能拿。一致性:新使用者、明確時間零點(第一張處方)。

③ 可交換性從哪借來

來自同適應症的主動對照(縮小嚴重度範圍)、新使用者設計(對齊時間零點、無不死時間),加上對 A、B 殘留嚴重度差的傾向分數校正。

④ 對應《What If》

混淆與可交換性;主動對照新使用者設計即目標試驗模擬(第 22 章)。Hernán & Robins, Causal Inference: What If (2020)。免費電子書。

⑥ 如果……?用反事實的語言看「盛行新使用者 PNU」

如果大家都用 A(Yᵃ⁼¹)vs 都用 B(Yᵃ⁼⁰)會怎樣?有盛行使用者時,可交換性在邊際上不成立:還在用 A 的,是易感者被耗竭後剩下的低風險存活者。PNU 改成在距起始時間(與體質)的條件下比較,把可交換性救回來。

由存活選擇造成的耗竭,用時間條件配對擋住

因果結構圖(DAG)

反事實介入圖(SWIG):治療節點拆成 A∣a、結果變成反事實 Yᵃ

看不懂這兩張圖?DAG 與 SWIG 的白話導讀

因果結構圖 DAG directed acyclic graph

把它想成「誰造成誰」的地圖。每個圓圈是一個變數(治療 A、結果 Y、混淆 U、共變項…);每個箭頭是一個直接的因果方向,A→Y 讀作「A 影響 Y」。看圖三步:(1) 從治療指到結果的箭頭,就是你想估的效果;(2) 任何不經過治療、卻同時連到治療與結果的路徑(後門 back door,通常就是混淆 U)會汙染估計;(3) 一個好的設計,本質就是想辦法把這些後門擋住,校正、配對、借工具、或自身對照。圖中紅色箭頭=偏誤來源,青色箭頭=你要的效果。

反事實介入圖 SWIG single-world intervention graph

SWIG 是把 DAG「動一刀」之後的反事實圖。它把治療節點切成兩半 A∣a:左半是真實世界觀察到的治療;右邊那個小 a,是「假如我們介入、把治療設成的值」。一旦這樣設定,下游所有結果就變成反事實 Yᵃ,「如果治療被設成 a,會發生的結果」。它的好處:把可交換性畫了出來,只要把該校正的校正掉,被設定的治療就和反事實獨立(A ⫫ Yᵃ),這時資料裡的關聯才等於因果效果。一句話:DAG 告訴你「世界長怎樣」;SWIG 告訴你「假想動手介入後,效果該怎麼讀」。

① 反事實與估計目標

在含盛行使用者的族群中,藥 A vs 對照藥 B 對結果率的效應,比只用新使用者更能代表真實在用藥的族群。

② 可交換性 · 正性 · 一致性

可交換性只在條件於距起始時間(與體質)下成立,因為盛行使用者是存活選出來的。正性:兩臂在相近的距起始時間都有人。一致性:治療定義明確、起始日可知。

③ 可交換性從哪借來

來自時間條件配對:把盛行使用者對齊到相同距起始時間的對照組(並校正體質/時間條件傾向分數),把耗竭與早期高風險的差異消掉。

④ 對應《What If》

選擇偏誤與存活選擇;時變混淆與條件在過去。Hernán & Robins, Causal Inference: What If (2020)。免費電子書。

⑥ 如果……?用反事實的語言看「陰性對照與近端因果 NC」

如果大家都接種(Yᵃ⁼¹)vs 都不接種(Yᵃ⁼⁰)會怎樣?一個未測的 U 讓 A 與 Yᵃ 不可交換,所以無法直接從資料讀出對比。陰性對照給了兩個 U 的代理;近端因果用它們在沒測到 U 的情況下辨識這個反事實對比。

未測的 U,加兩個陰性對照代理

因果結構圖(DAG)

反事實介入圖(SWIG):治療節點拆成 A∣a、結果變成反事實 Yᵃ

看不懂這兩張圖?DAG 與 SWIG 的白話導讀

因果結構圖 DAG directed acyclic graph

把它想成「誰造成誰」的地圖。每個圓圈是一個變數(治療 A、結果 Y、混淆 U、共變項…);每個箭頭是一個直接的因果方向,A→Y 讀作「A 影響 Y」。看圖三步:(1) 從治療指到結果的箭頭,就是你想估的效果;(2) 任何不經過治療、卻同時連到治療與結果的路徑(後門 back door,通常就是混淆 U)會汙染估計;(3) 一個好的設計,本質就是想辦法把這些後門擋住,校正、配對、借工具、或自身對照。圖中紅色箭頭=偏誤來源,青色箭頭=你要的效果。

反事實介入圖 SWIG single-world intervention graph

SWIG 是把 DAG「動一刀」之後的反事實圖。它把治療節點切成兩半 A∣a:左半是真實世界觀察到的治療;右邊那個小 a,是「假如我們介入、把治療設成的值」。一旦這樣設定,下游所有結果就變成反事實 Yᵃ,「如果治療被設成 a,會發生的結果」。它的好處:把可交換性畫了出來,只要把該校正的校正掉,被設定的治療就和反事實獨立(A ⫫ Yᵃ),這時資料裡的關聯才等於因果效果。一句話:DAG 告訴你「世界長怎樣」;SWIG 告訴你「假想動手介入後,效果該怎麼讀」。

① 反事實與估計目標

在未測混淆下,A 對 Y 的平均因果效應(Yᵃ⁼¹ − Yᵃ⁼⁰),用一對陰性對照做近端辨識。

② 可交換性 · 正性 · 一致性

邊際可交換性不成立(U 未測),改用代理條件:A↛W(有效 NCO)、Z↛Y(有效 NCE)、兩者都與 U 相關,加完備性。正性:給定代理下治療有變異。一致性:暴露定義明確。

③ 可交換性從哪借來

來自混淆橋:陰性對照暴露 Z 與結果 W 是 U 的代理,混淆橋函數讓你把 U 的效應扣掉(線性情形=P2SLS),把不可辨識變成可辨識。

④ 對應《What If》與近端文獻

混淆與可交換性(Hernán & Robins, What If, 2020);陰性對照(Lipsitch 2010)與近端因果學習(Miao 2018;Tchetgen Tchetgen 等)。免費電子書。

⑥ 如果……?用反事實的語言看「中介分析 MED」

中介分析問的是一個巢狀反事實:如果大家都接種,但抗體被固定在「沒接種會有的水準」,Yᵃ⁼¹˒ᴹ⁽⁰⁾,感染會怎樣?比較這種跨世界的量,正是把效果拆成透過中介(NIE)與繞過中介(NDE)的方法。

中介 DAG:A → M → Y,外加直接 A → Y

因果結構圖(DAG)

反事實介入圖(SWIG):治療節點拆成 A∣a;結果變成跨世界反事實 Yᵃ˒ᴹ⁽ᵃ*⁾

看不懂這兩張圖?DAG 與 SWIG 的白話導讀

因果結構圖 DAG directed acyclic graph

把它想成「誰造成誰」的地圖。每個圓圈是一個變數(治療 A、結果 Y、混淆 U、共變項…);每個箭頭是一個直接的因果方向,A→Y 讀作「A 影響 Y」。看圖三步:(1) 從治療指到結果的箭頭,就是你想估的效果;(2) 任何不經過治療、卻同時連到治療與結果的路徑(後門 back door,通常就是混淆 U)會汙染估計;(3) 一個好的設計,本質就是想辦法把這些後門擋住,校正、配對、借工具、或自身對照。圖中紅色箭頭=偏誤來源,青色箭頭=你要的效果。

反事實介入圖 SWIG single-world intervention graph

SWIG 是把 DAG「動一刀」之後的反事實圖。它把治療節點切成兩半 A∣a:左半是真實世界觀察到的治療;右邊那個小 a,是「假如我們介入、把治療設成的值」。一旦這樣設定,下游所有結果就變成反事實 Yᵃ,「如果治療被設成 a,會發生的結果」。它的好處:把可交換性畫了出來,只要把該校正的校正掉,被設定的治療就和反事實獨立(A ⫫ Yᵃ),這時資料裡的關聯才等於因果效果。一句話:DAG 告訴你「世界長怎樣」;SWIG 告訴你「假想動手介入後,效果該怎麼讀」。

① 反事實與估計目標

兩個估計目標:NDE = Y^{1,M(0)} − Y^{0,M(0)}(動 A、把中介固定在沒接種的值)與 NIE = Y^{1,M(1)} − Y^{1,M(0)}(固定 A=1、搬動中介)。兩者相加=總效果。

② 可交換性 · 正性 · 一致性

自然效果需要序列可交換:無未測的 A–Y、A–M、以及(命門)M–Y 混淆,加上跨世界(cross-world)「無暴露誘發的 M–Y 混淆」條件。正性:兩種治療下每個中介值都可能出現。一致性:A 與 M 定義明確。

③ 可交換性從哪借來

沒有自動來源,和其他設計不同,把 A 隨機分派換不到 M–Y 的可交換。M–Y 這條只能靠已測共變項+敏感度分析;若跨世界(cross-world)條件可疑,改估控制直接效果(固定 M)。

④ 對應《What If》與中介文獻

中介、自然與控制直接效果、跨世界假設(Hernán & Robins, What If, 第 21 章);Imai, Keele & Yamamoto;VanderWeele 2015。免費電子書。

⑥ 如果……?用反事實的語言看「傾向分數 PS」

估計目標是兩個反事實的對比:如果大家都接種(Yᵃ⁼¹)vs 如果都不接種(Yᵃ⁼⁰),結果會差多少?兩組在嚴重度 X 上不同, 所以原始比較被混淆。PS 方法把經過 X 的後門擋住,對分數做配對或加權,讓接種與未接種在 X 下可交換,校正後的對比就等於因果效果。

PS 的 DAG:X 是 A 與 Y 的後門混淆

因果結構圖(DAG)

反事實介入圖(SWIG):治療節點拆成 A∣a、結果變成反事實 Yᵃ

看不懂這兩張圖?DAG 與 SWIG 的白話導讀

因果結構圖 DAG directed acyclic graph

把它想成「誰造成誰」的地圖。每個圓圈是一個變數(治療 A、結果 Y、混淆 U、共變項…);每個箭頭是一個直接的因果方向,A→Y 讀作「A 影響 Y」。看圖三步:(1) 從治療指到結果的箭頭,就是你想估的效果;(2) 任何不經過治療、卻同時連到治療與結果的路徑(後門 back door,通常就是混淆 U)會汙染估計;(3) 一個好的設計,本質就是想辦法把這些後門擋住,校正、配對、借工具、或自身對照。圖中紅色箭頭=偏誤來源,青色箭頭=你要的效果。

反事實介入圖 SWIG single-world intervention graph

SWIG 是把 DAG「動一刀」之後的反事實圖。它把治療節點切成兩半 A∣a:左半是真實世界觀察到的治療;右邊那個小 a,是「假如我們介入、把治療設成的值」。一旦這樣設定,下游所有結果就變成反事實 Yᵃ,「如果治療被設成 a,會發生的結果」。它的好處:把可交換性畫了出來,只要把該校正的校正掉,被設定的治療就和反事實獨立(A ⫫ Yᵃ),這時資料裡的關聯才等於因果效果。一句話:DAG 告訴你「世界長怎樣」;SWIG 告訴你「假想動手介入後,效果該怎麼讀」。

① 反事實與估計目標

對比 E[Yᵃ⁼¹] − E[Yᵃ⁼⁰] = ATE(用 IPTW/重疊權重)或 ATT(用 PS 配對,接種者身上的效果)。估計目標由你用哪種權重決定。

② 可交換性 · 正性 · 一致性

條件可交換性:在已測 X 下,接種近似隨機(無未測混淆)。正性:每人 0 < PS < 1(重疊)。一致性:接種定義明確。PS 平衡 X 來換取第一條。

③ 可交換性從哪借來

只靠已測共變項。PS 讓比較在你放進去的 X 上公平,它無法替未測混淆製造可交換。這個缺口正是「無未測混淆」成為頭號假設的原因。

④ 對應《What If》與 PS 文獻

混淆、後門校正、IPW 與傾向分數(Hernán & Robins, What If, 第 7、12–15 章);Rosenbaum & Rubin 1983;Austin 2011;Li, Morgan & Zaslavsky 2018。免費電子書。

⑥ 如果……?用反事實的語言看「TMLE/雙重穩健」

估計目標和傾向分數相同:E[Yᵃ⁼¹] − E[Yᵃ⁼⁰],即 ATE。DAG 也是同一張後門圖(X 混淆 A 與 Y)。不同的是估計器: TMLE/AIPW 用兩個描述這個結構的模型,結果迴歸與傾向分數,所以其一對就不偏,而 TMLE 多做的目標化(targeting)步驟讓插入式估計更有效率。

TMLE 的 DAG:X 是後門混淆;兩個模型、兩次機會

因果結構圖(DAG)

反事實介入圖(SWIG):治療節點拆成 A∣a、結果變成反事實 Yᵃ

看不懂這兩張圖?DAG 與 SWIG 的白話導讀

因果結構圖 DAG directed acyclic graph

把它想成「誰造成誰」的地圖。每個圓圈是一個變數;每個箭頭是一個直接因果方向。治療指到結果的箭頭就是你要的效果;任何不經過治療、卻同時連到治療與結果的路徑(後門,通常是混淆)會汙染估計;好設計把後門擋住。紅箭頭=偏誤、青箭頭=效果。

反事實介入圖 SWIG single-world intervention graph

SWIG 是把 DAG「動一刀」之後的反事實圖。把治療節點切成 A∣a:左半是觀察到的治療,小 a 是你介入要設的值。下游結果都變成反事實 Yᵃ。它把可交換性畫出來:校正後,被設定的治療與反事實獨立(A ⫫ Yᵃ),這時關聯才等於因果效果。

① 反事實與估計目標

對比 E[Yᵃ⁼¹] − E[Yᵃ⁼⁰] = ATE。TMLE 直接對這個插入式估計做目標化(targeting);AIPW 則用雙重穩健的影響函數公式來估它。

② 可交換性 · 正性 · 一致性

和 PS 相同三條,條件可交換(無未測混淆)、正性(0<PS<1)、一致性。雙重穩健不放寬任何一條;它只防把輔助模型配錯。

③ 穩健性從哪來

來自對同一結構有兩個模型。結果模型對,擴增項期望為零;傾向分數對,插入式偏誤被修正。你只需要其中一個對,這就是「兩次機會」。

④ 對應《What If》與 TMLE 文獻

標準化/g-formula、IPW 與雙重穩健估計(Hernán & Robins, What If, 第 13–15 章);van der Laan & Rubin 2006;van der Laan & Rose 2011;Luque-Fernandez 等 2018。免費電子書。

⑥ 如果……?用反事實的語言看「G-methods/時變混淆」

估計目標是治療策略的反事實對比:E[Y^(1,1)] − E[Y^(0,0)],即「大家全程用藥 vs 全程不用」的結果。DAG 的關鍵在: L₁ 落在 A₀ → L₁ → Y 這條路上(是中介,所以不能條件在它上)卻又 L₁ → A₁(是第二劑的混淆,所以必須處理它)。 g-methods 用標準化(g-formula)或加權(IPTW)取代「條件控制」,化解這個兩難。

G-methods 的 DAG:L₀→A₀→L₁→A₁→Y 的治療↔混淆回饋

因果結構圖(DAG)

反事實介入圖(SWIG):治療節點拆成 A₀∣a₀、A₁∣a₁,結果變成策略反事實 Yᵃ

看不懂這兩張圖?DAG 與 SWIG 的白話導讀

因果結構圖 DAG directed acyclic graph

把它想成「誰造成誰」的地圖。每個圓圈是一個變數;每個箭頭是一個直接因果方向。治療指到結果的箭頭就是你要的效果;一個被過去治療造成、又造成未來治療與結果的共變項(這裡的 L₁)就是難題,它同時是混淆又是中介。紅箭頭=偏誤、青箭頭=效果。

反事實介入圖 SWIG single-world intervention graph

SWIG 是把 DAG「動一刀」之後的反事實圖。這裡把兩個治療都切開(A₀∣a₀、A₁∣a₁),讀出策略反事實 Yᵃ。識別需要序列可交換,每個時點、在過去之下,被設定的治療與 Yᵃ 獨立,這正是標準化(g-formula)或反機率加權(IPTW)所提供的。

① 反事實與估計目標

對比 E[Y^(1,1)] − E[Y^(0,0)],一個靜態策略(全程用 vs 全程不用)的效果,不是單一劑量。g-methods 也能估動態策略(「當 Lₜ 超過門檻才用」)。

② 可交換性 · 正性 · 一致性

每個時點的序列可交換(無未測時變混淆);每個時點與史的正性;一致性/策略定義明確。這是 PS 單時點版本的時變推廣。

③ 為什麼一般迴歸會失敗

條件在 L₁ 上會擋掉 A₀→L₁→Y 那段效果(它是中介)又開啟對撞(L₁←A₀、L₁←U→Y);不條件又讓 L₁ 混淆 A₁。沒有單一迴歸能同時做到,只有標準化或加權可以。

④ 對應《What If》與 g-methods 文獻

時變治療、g-formula、MSM 與 IPW、g-estimation(Hernán & Robins, What If, 第三部);Robins, Hernán & Brumback 2000;Naimi, Cole & Kennedy 2017;Daniel 等 2013。免費電子書。

⑥ 如果……?用反事實的語言看「陰性檢驗設計 TND」

估計目標是疫苗效力的對比(VE),但這個設計其實是處理選樣的巧招。「有被檢驗」是一個對撞:症狀(來自目標感染或其他)與就醫傾向都指向「被檢驗」。 對「被檢驗」抽樣本可能開啟偏誤,但選陰性對照(通過了同一道就醫濾網)讓這個選樣相對於接種是非差別的,勝算比因此仍辨識 VE。

TND 的 DAG:就醫傾向 H → 接種與被檢驗;條件在「被檢驗」(對撞)上

因果結構圖(DAG)

反事實介入圖(SWIG):把接種設成 a → 反事實 Yᵃ(目標感染)

看不懂這兩張圖?DAG 與 SWIG 的白話導讀

因果結構圖 DAG directed acyclic graph

把它想成「誰造成誰」的地圖。每個圓圈是一個變數;每個箭頭是一個直接因果。有兩個箭頭指進去的節點是對撞,條件在它上(這裡是只取「被檢驗」的人)可能造出假關聯,除非對照選得讓它維持非差別。

反事實介入圖 SWIG single-world intervention graph

SWIG 是把 DAG「動一刀」之後的反事實圖。把接種設成 a,讀反事實的目標感染 Yᵃ。若在被檢驗者中接種與 Yᵃ 獨立,TND 就辨識 VE = 1 − OR,這在「陰性對照與 case 共享就醫傾向、且疫苗不影響對照疾病」時成立。

① 反事實與估計目標

VE = 1 −(接種 vs 未接種的目標感染風險/勝算比),目標病原的 Yᵃ⁼¹ vs Yᵃ⁼⁰ 對比。對照有效時,檢驗者中的 OR 就估它。

② 靠選樣換來可交換

和 PS(條件在共變項)不同,TND 靠抽樣對象達成可比:限制在被檢驗者,讓就醫傾向成為 case 與 control 共有,於是不再混淆接種。

③ 哪裡仍可能破

若疫苗影響對照疾病(C2)、接種者在相同症狀下就醫不同(C3)、或檢驗錯分(C1),選樣就變差別、VE 偏。其他已測混淆仍要調整(⑤)。

④ 對應 TND 文獻

陰性檢驗設計與其因果基礎(Jackson & Nelson 2013;Sullivan, Tchetgen Tchetgen & Cowling 2016;Vandenbroucke & Pearce 2019;Schnitzer 2022;Andrews 等 2025)。選樣/對撞偏誤亦見 Hernán & Robins, What If, 第 8 章。

⑥ 如果……?用反事實的語言看「處方順序對稱 PSSA」

PSSA 是自身對照的篩檢:每個用過兩種藥的人當自己的對照,所有時間不變的混淆(性別、基因、穩定體質)都相消,不需要讓不同人可比。它指向的反事實是「若沒用 A,B 還會被開立嗎?」自身對照唯一去不掉的是時變的力量,處方趨勢,而那正是 SRnull 除掉的東西。

PSSA 的 DAG:在個人內,趨勢(日曆時間)是唯一還要去掉的東西

因果結構圖(DAG)

反事實介入圖(SWIG):把指標藥 A 設成 a → 反事實的標記藥起始 Bᵃ

看不懂這兩張圖?DAG 與 SWIG 的白話導讀

因果結構圖 DAG directed acyclic graph

把它想成「誰造成誰」的地圖。每個圓圈是一個變數;每個箭頭是一個直接因果。自身對照(個人內比較)默默擋住所有經由時間不變特質的後門,它們在同一個人內不會變。剩下的是驅動 B 何時被開立的日曆時間趨勢;SRnull 就是去掉它的裝置。

反事實介入圖 SWIG single-world intervention graph

SWIG 是把 DAG「動一刀」之後的反事實圖。把指標藥 A 設成 a,讀反事實的標記藥起始 Bᵃ。PSSA 從起始順序的不對稱讀出瀑布;一旦趨勢(唯一的時變後門)被 SRnull 除掉、且瀑布方向合理,aSR 就辨識它。

① 反事實與估計目標

目標是 A 造成的順序不對稱:若沒用 A,「B 接在 A 後」會和「A 接在 B 後」一樣常見嗎?aSR > 1 表示 A 讓 B 更可能跟著來,候選瀑布。

② 靠自身對照換來可交換

和 SCCS 一樣,可比來自個人內對比:時間不變混淆自動相消。PSSA 不調整共變項,而是用設計把它們去掉。

③ 哪裡仍可能破

瀑布方向錯(C1)、趨勢建模錯(C2)、時間窗不當(C3)、盛行使用者(C4)、或不一致對太少(C5)都會扭曲 aSR。PSSA 只標、不確認,要用控混淆的設計追下去。

④ 對應 PSSA 文獻

處方順序對稱分析(Hallas 1996;Tsiropoulos 等 2009;Hendrix 等 2024 報告指引)。自身對照/個人內可交換亦是 SCCS 的基礎;時變結構見 Hernán & Robins, What If。

⑥ 如果……?用反事實的語言看「樹狀掃描 TreeScan」

TreeScan 本質上是篩檢機器、不是效果估計器,所以它真正的反事實問題很樸素:「在哪個結果節點,暴露下的風險高於『沒用藥時會有的風險』?」這裡更深的想法不是辨識單一效果,而是把多重性控制好:當你一次在數千個節點問這個問題,真正重要的反事實是整個虛無世界,若藥到處都沒作用,最極端的節點會長怎樣。排列法的最大 LLR 就是那個被模擬出來的虛無世界。

TreeScan 的 DAG:暴露 → 結果節點;排列虛無回答「若藥沒作用會如何?」

因果結構圖(DAG)

反事實介入圖(SWIG):把暴露設成 a → 反事實的結果節點風險 Yᵃ

看不懂這兩張圖?DAG 與 SWIG 的白話導讀

因果結構圖 DAG directed acyclic graph

把它想成「誰造成誰」的地圖。每個圓圈是一個變數;每個箭頭是一個直接因果。TreeScan 在每個結果節點問「暴露是否抬高風險」,但一條後門(未建模的混淆 U 同時指向暴露與「落在哪個節點」)會偽造訊號。排列虛無只在沒有這種 U 作怪時才有效(見 ④ C4)。

反事實介入圖 SWIG single-world intervention graph

SWIG 是把 DAG「動一刀」之後的反事實圖。把暴露設成 a,讀每個節點的反事實風險 Yᵃ。當某節點觀察到的暴露超額,極端到不可能是「無效果世界」裡最極端的那個節點時,TreeScan 就把它標出,那個無效果世界,正是排列(打亂標籤)的虛無。

① 反事實與估計目標

在每個節點:暴露風險是否高於它的「沒用藥」反事實?估計目標不是單一效果,而是一組節點層級的超額,用一份族系錯誤率預算一起篩。

② 被模擬的虛無世界

可比不是來自調整共變項,而是來自排列虛無:打亂暴露標籤建出「藥沒作用」的世界,再問真實的最大 LLR 對它而言夠不夠極端。

③ 哪裡仍可能破

若有混淆同時驅動暴露與結果節點(C4),或各節點基準非常數(C2),虛無世界就錯了、標記有偏。TreeScan 只標、不確認,要用控混淆的設計追下去。

④ 對應 TreeScan 文獻

樹狀掃描統計(Kulldorff 等 2003;Maro 等 2014, FDA Sentinel)。自身對照/個人內比較把它和 SCCS、PSSA 連起來;選樣與多重性亦見 Hernán & Robins, What If。

⑥ 如果……?用反事實的語言看「加權累積暴露 WCE」

WCE 指向的反事實很豐富:不是「有沒有治療」,而是「在這整段加權暴露史下、相對於另一段,你的風險會是多少?」權重曲線其實是在說「過去哪一個版本的你對今天的風險最重要」。常見的陷阱和 g-methods 擔心的一樣:若你隨時間變化的病情既驅動你的用藥增減、又驅動結果,那麼比較不同暴露史就不是「拿同類比同類」,一個時變混淆卡在路徑上。

WCE 的 DAG:時變混淆 L(病情)同時驅動用藥增減與結果

因果結構圖(DAG)

反事實介入圖(SWIG):把暴露史設成 a → 反事實風險 Yᵃ

看不懂這兩張圖?DAG 與 SWIG 的白話導讀

因果結構圖 DAG directed acyclic graph

把它想成「誰造成誰」的地圖。每個圓圈是一個變數;每個箭頭是一個直接因果。每個時點的暴露 A_t 影響結果;但時變混淆 L_t(病情)同時指向 A_t(你因為病重而改藥)與結果,這是一條後門,不處理就會偏掉暴露與結果的關聯。

反事實介入圖 SWIG single-world intervention graph

SWIG 是把 DAG「動一刀」之後的反事實圖。把整段暴露史設成某個型態 a,讀反事實風險 Yᵃ。WCE 透過加權摘要估這段歷史的效果;辨識需要「在已測(最好是時變)共變項下,加權暴露近似隨機」,正是 ④ C4 在講的假設。

① 反事實與估計目標

估計目標是兩段加權暴露史之間的風險比,例如「持續近期用藥」vs「都沒用」。權重曲線說明過去每個月的劑量各貢獻多少,所以對比的是整段軌跡,而非單一的有無標籤。

② 可比從哪來

WCE 在風險模型裡校正已測共變項。若在這些之下你的加權暴露近似隨機,即用藥增減不是被「同時驅動結果的未測因子」帶動,可比就成立。

③ 哪裡仍可能破

經典的失效是時變適應症混淆(C4):惡化的病情改變用藥又拉高風險。單一基線校正修不了,要用時變方法(邊際結構 Cox/g-methods)。

④ 對應 WCE 文獻

加權累積暴露+樣條權重(Sylvestre & Abrahamowicz 2009;Abrahamowicz 等)。時變混淆與 g-methods:Hernán & Robins, What If 第三部。

⑥ 如果……?用反事實的語言看「可轉移性」

你要的是目標族群的反事實對比 Yᵃ⁼¹ − Yᵃ⁼⁰,但你只在研究裡看到它。一個選樣節點 S(研究 vs 目標)壓在效果修飾子 X 上;只要在給定 X 下 S 與反事實獨立(沒有未測、且分布不同的修飾子),就能用對 X 標準化/加權把目標效果救回來。

可轉移性的 DAG/SWIG:選樣壓在效果修飾子上

因果結構圖(DAG)

反事實介入圖(SWIG):把治療設成 a → 目標的反事實 Yᵃ

① 反事實與估計目標

目標族群的平均效果 E_target[Yᵃ⁼¹ − Yᵃ⁼⁰],不是研究的。

② 辨識條件

在 X 下對選樣可交換(S ⫫ Yᵃ | X)、選樣正性(目標 ⊆ 研究支持)、一致性、效果修飾子兩邊都量到。

③ 可交換性從哪借

來自「量到每一個在兩族群分布不同的效果修飾子」,標準化/加權再把差異消掉。

④ 對應文獻

Adamson 等 2026(ISPE 框架);Inoue & Hsu 2024;Westreich/Edwards/Lesko;Dahabreh 等;Bareinboim & Pearl。免費書:Hernán & Robins, What If。

⑥ 如果……?用反事實的語言看「外部對照」

你要的是試驗族群的對比 Yᵃ⁼¹ − Yᵃ⁼⁰,但你只觀察到 Yᵃ⁼¹(大家都被治療)。外部對照提供 Yᵃ⁼⁰,但只有在給定已測共變項 X 下、一個人落在哪個臂(S:試驗 vs 外部)與他未治療的結果 Yᵃ⁼⁰ 獨立時才有效。這就是借來對照的可交換性;對 X 標準化/加權就是讓它成立的手段。

外部對照的 DAG/SWIG:選樣(臂別)壓在共變項上

因果結構圖(DAG)

反事實介入圖(SWIG):把治療設成 a → 借來的臂提供 Yᵃ

① 反事實與估計目標

試驗族群的治療效果 E[Yᵃ⁼¹ − Yᵃ⁼⁰];試驗給 Yᵃ⁼¹,外部臂給 Yᵃ⁼⁰。

② 辨識條件

外部對照在 X 下可交換(S ⫫ Yᵃ⁼⁰ | X)、正性(試驗 ⊆ 外部支持)、結果定義一致且良好、無時代/來源效應。

③ 可交換性從哪借

來自「量到每一個在兩臂間不同的預後因子」,標準化/加權再把不平衡消掉。(同期隨機化會免費給你;這裡得靠自己做到。)

④ 對應文獻

ICH E10;Pocock 1976;Schmidli 等 2014(動態借用);Burcu 等 2020;Jahanshahi 等 2021。免費書:Hernán & Robins, What If(目標試驗與可轉移性)。

多準則決策分析(MCDA):當準則互相衝突時怎麼選

本工具箱其他方法都在估計效果。MCDA 是在那之後的一層:當你有了數字,要怎麼在「有些準則好、有些準則差」的選項間做決定,一個更有效、但更危險也更貴的藥?MCDA 把取捨攤開:列出準則、替每個選項在每個準則上評分、給權重反映各準則有多重要,再合成一個總分或排名。它是醫療科技評估(HTA)與法規效益–風險評估的骨幹。

五個步驟

① 準則,挑出重要的面向(療效、安全、成本、方便性……),最好彼此不重疊。② 績效矩陣,替每個選項在每個準則上評分。③ 正規化,把準則放到共同的 0–1 尺度(並把「成本型、越低越好」的反向)。④ 加權與合成,乘上權重再加總(簡單加權/MAVT),或用 TOPSIS/PROMETHEE/ELECTRE/AHP。⑤ 敏感度,變動權重,看冠軍是否穩健。

常見方法

加權總和/MAVT(本頁示範)最透明。AHP 用兩兩比較推出權重。TOPSIS 依「離理想點的距離」排名;PROMETHEE/ELECTRE 用帶偏好門檻與否決的優劣關係法(outranking)。

在醫療的應用

法規的效益–風險評估(EMA、FDA 框架)、HTA 與藥品給付決策、介入排序、以及醫病共享決策。ISPOR 出版了醫療 MCDA 的良好實務指引。

它是什麼、不是什麼

MCDA 不產生證據,它把(本工具其他方法估到的)效果估計,連同明確的價值判斷一起合成。它的透明正是優點:權重被寫下來、可以被討論,而不是藏在某人腦中。

看專有名詞解釋

多準則決策分析 multi-criteria decision analysis (MCDA)

一組結構化方法,用來同時依多個互相衝突的準則評估選項:把績效矩陣(選項×準則)與準則權重合成為總體評價或排名。在醫療領域支撐效益–風險與 HTA 決策(Thokala 等 2016;Marsh 等 2016,ISPOR)。

② 互動:拉動權重,看排名怎麼變

四個治療、四個準則的(合成)績效矩陣。拉動「每個準則有多重要」,長條會依加權總分即時重新排名。沒有唯一「正確」答案,排名就是你的價值觀說了算,而且被攤開來看。

治療療效安全成本(越低越好)方便性
新藥 A90608070
老藥 B65852080
生物製劑 C95709540
學名藥 D60801090

每個準則用 min-max 正規化到 0–1(成本反向);總分是「權重占比」的加權總和。這是簡單加權(MAVT)模型,TOPSIS/PROMETHEE 排名會略有不同,但故事一樣。

③ 實際做:建矩陣、給權重、合成

流程

定義準則與明確的評分尺度、填好績效矩陣、引出權重(swing weighting、AHP 兩兩比較、或利害關係人小組)、正規化、合成,再對權重做敏感度分析。記錄是誰、為何這樣設權重。


程式(SAS · R · Stata):多準則決策分析(加權總和效益-風險)

這是可直接在可下載的 mcda_sample.csv 上完整執行的程式(欄位:alternative, efficacy, safety, convenience, cost)。

SAS — 正規化、加權、排序

/* read the sample file */
proc import datafile="mcda_sample.csv" out=d dbms=csv replace;
    getnames=yes;
run;
/* min-max range per criterion (cost is inverted: lower is better) */
proc means data=d min max noprint;
    var efficacy safety convenience cost;
    output out=r min=e0 s0 c0 k0 max=e1 s1 c1 k1;
run;
data score; if _n_=1 then set r; set d;
    nE=(efficacy-e0)/(e1-e0); nS=(safety-s0)/(s1-s0);
    nC=(convenience-c0)/(c1-c0); nK=(k1-cost)/(k1-k0);
    /* weights sum to 1 */
    score = 0.40*nE + 0.30*nS + 0.20*nC + 0.10*nK;
run;
proc sort data=score; by descending score; run;
proc print data=score; var alternative score; run;

資料步驟正規化(將成本反轉)並套用權重向量;PROC SORT 對方案排序。

R — 加權總和計分與排序

# read the sample file
d <- read.csv("mcda_sample.csv")
# min-max normalize to 0-1; cost is lower-is-better, so invert it
nrm <- function(v) (v - min(v)) / (max(v) - min(v))
N <- data.frame(efficacy = nrm(d$efficacy), safety = nrm(d$safety),
                convenience = nrm(d$convenience), cost = 1 - nrm(d$cost))
# stakeholder weights (sum to 1)
w <- c(efficacy = 0.40, safety = 0.30, convenience = 0.20, cost = 0.10)
d$score <- as.matrix(N) %*% w
# rank alternatives (MCDA::weightedSum() does the same)
print(d[order(-d$score), c("alternative", "score")])

加權總和分數對方案排序;MCDA 套件的 weightedSum() 可重現此結果。

Stata — egen/gen 加權總和

* read the sample file
import delimited "mcda_sample.csv", clear case(preserve)
* min-max normalize each criterion; invert cost (lower is better)
foreach v in efficacy safety convenience {
    egen mn_`v' = min(`v')
    egen mx_`v' = max(`v')
    gen n_`v' = (`v' - mn_`v') / (mx_`v' - mn_`v')
}
egen mnc = min(cost)
egen mxc = max(cost)
gen n_cost = (mxc - cost) / (mxc - mnc)
* weights sum to 1; score and rank
gen score = .40*n_efficacy + .30*n_safety + .20*n_convenience + .10*n_cost
gsort -score
list alternative score

egen 建立範圍;gsort 依加權分數排序方案。

④ 假設與陷阱

權重是價值,不是事實

結果完全取決於權重,而權重編碼的是誰的偏好。不同利害關係人(法規、付費者、病人)排名不同,要說明用了誰的價值,並一定附上權重敏感度分析(⑥ 分頁)。

重複計算與壞尺度

重疊的準則(例如兩個都在量「安全」)會偷偷把那個面向加倍加權。評分尺度沒選好(價值非線性、範圍錯)會扭曲每個方法。準則應彼此偏好獨立、價值函數要站得住腳。

排名反轉

有些方法(TOPSIS、ELECTRE)在加入或移除一個不相關的第三選項時,可能反轉兩個選項的順序。要了解所用方法的行為;簡單加權總和沒有這問題,但會以別的方式掩蓋不可傳遞性。

⑤ 用 AI/ML 強化:機器學習能幫 MCDA 什麼

MCDA 需要兩樣東西,績效數字與權重。機器學習能幫忙提供這兩者,但永遠提供不了「價值」本身。

填績效矩陣

ML/預測模型可以產生餵進矩陣的準則分數,例如 NTUA 的範例先用 LSTM 預測當輸入,再用 TOPSIS/PROMETHEE/ELECTRE 對選項排名。

學出權重

偏好學習/逆向 MCDA 從過去的決策反推準則權重;AHP 式的一致性檢查能標出矛盾的輸入,當小組說不出明確權重時很有用。

ML 給不了的

從歷史學權重只是複製過去的價值(連同其偏誤)。應該採計誰的偏好是倫理/治理問題,不是預測。讓權重保持透明、可被挑戰。

⑥ 如果……?換誰的權重,冠軍還站得住嗎

真正的 MCDA 問題是反事實的:在不同但合理的權重下,決定會不會改變?把 ② 的滑桿當成即時的敏感度分析。

如果付費者很看重成本?

在 ② 把成本權重拉高,便宜的選項(學名藥 D、老藥 B)就上升;把療效拉高,新藥/生物製劑就贏。只有在某一方權重下才贏的選擇,是脆弱的。

如果冠軍從不改變?

如果某個選項在整個合理權重範圍內都維持第一,這個決定就穩健,是真正有力的建議。這才是 MCDA 最有用的產出,勝過任何單一排名。

配上證據的不確定性

矩陣裡的分數本身是帶信賴區間的估計。完整的分析會同時變動權重(價值)與績效分數(證據),後者正來自本工具箱的因果方法。

模糊集質性比較分析(fsQCA):哪些「條件組合」會產生結果?

迴歸問的是「每個變數、在固定其他變數下的平均淨效果」。fsQCA(Ragin)改問一個集合論的問題:哪些條件的組合,對結果而言是充分(或必要)的?它擁抱等效性(equifinality,殊途同歸)(不同的「配方」可以通往同一個結果)與因果不對稱(造成「結果不發生」的配方,不只是把這個配方反過來的鏡像)。它在中小樣本、且條件由理論驅動時最有用,常見於衛生服務、政策與實施研究。

工作流程

① 校準,用實質定義的錨點,把每個原始變數轉成 [0,1] 的模糊隸屬度(完全屬於 ≈ 0.95、交叉點 = 0.5、完全不屬於 ≈ 0.05)。② 真值表,列出條件的所有邏輯可能組合,以及案例如何分布。③ 必要性與充分性,評估哪些條件/組合對結果是必要、或充分。④ 最小化,把一致的組合用布林邏輯化簡成精簡解。

是集合,不是變數

條件是案例「依程度隸屬」的集合(模糊隸屬度 0–1)。組合用布林邏輯:AND=取最小隸屬度、OR=取最大、NOT=1 − 隸屬度。

充分 vs 必要

充分:只要組合出現、結果就出現(每個案例 X 的隸屬度 ≤ Y 的隸屬度,點在對角線上方)。必要:結果只在該條件出現時才發生(X ≥ Y)。② 的圖示範充分性。

一致性與覆蓋率

一致性=資料有多貼近這個集合關係(充分性用 Σmin(X,Y)/ΣX);常見門檻 ≥ 0.80。覆蓋率=該組合解釋了多少結果(Σmin(X,Y)/ΣY),一個配方的經驗重要性。

看專有名詞解釋

模糊集質性比較分析 fuzzy-set qualitative comparative analysis (fsQCA)

一種集合論、組態式的方法(Ragin 2008):把條件校準成模糊隸屬度,並用真值表的布林最小化,找出對結果「一致地充分(或必要)」的條件組合,以一致性與覆蓋率摘要。它為「多元並發因果、等效性、因果不對稱」而設計,而非估計平均淨效果。

② 互動:某個條件組合對結果是否充分?

十二個案例,每個都有對條件 A、B 與對結果 Y 的模糊隸屬度。選一個條件組合,看集合論的充分性圖:每個點是一個案例(x=它對該組合的隸屬度、y=它對結果的隸屬度)。充分=點落在對角線上(或上方)(X ⊆ Y)。一致性與覆蓋率即時更新,注意「A 且 B」比單獨 A 或 B 更一致(落在線下方的紅點更少)。

紅點違反充分性(結果隸屬度低於組合隸屬度)。一致性 = Σmin(X,Y)/ΣX、覆蓋率 = Σmin(X,Y)/ΣY(Ragin 2006)。合成教學資料。

③ 實際做:校準、真值表、最小化

步驟

從理論挑條件;對每個校準(直接法:設三個錨點,0.95/0.5/0.05);建真值表;設一致性門檻(常 ≥ 0.8,並對案例數設頻次門檻);布林最小化得到保守/中間/精簡解;對每條路徑報一致性與覆蓋率;對校準與門檻做穩健性檢查。


程式(SAS · R · Stata):模糊集質性比較分析(fsQCA)

出處 — 程式碼即 R QCA 套件的標準呼叫:truthTable(outcome=, conditions=, incl.cut=) 建真值表,再以 minimize(tt, details=TRUE) 做布林最小化並輸出一致性與覆蓋率;用法同 QCA 套件官方參考手冊與 vignette(Duşa, Journal of Statistical Software / QCA reference manual, CRAN)。SAS 與 Stata 段落僅為讀檔檢視,因兩者無標準 QCA 程序。

這是可直接在可下載的 fsqca_sample.csv 上完整執行的程式(欄位:case, A, B, C, Y;A/B/C/Y 已校準為 0-1 集合隸屬度)。

SAS — 說明:QCA 於 R 進行

/* read the sample file */
proc import datafile="fsqca_sample.csv" out=d dbms=csv replace;
    getnames=yes;
run;
/* SAS has no standard QCA procedure; just view the calibrated memberships. */
/* The truth-table minimization is run in R (QCA package) below. */
proc print data=d; run;

SAS 沒有標準的 QCA 實作;標準做法是用 R 的 QCA 套件。

R — truthTable() + minimize()

# read the sample file (A,B,C,Y are calibrated 0-1 memberships)
d <- read.csv("fsqca_sample.csv", row.names = "case")
library(QCA)
# build the truth table for outcome Y given conditions A, B, C
tt <- truthTable(d, outcome = "Y", conditions = c("A", "B", "C"),
                 incl.cut = 0.8, show.cases = TRUE)
print(tt)
# minimize to the sufficient configurations with consistency & coverage
sol <- minimize(tt, details = TRUE)
print(sol)

incl.cut = 0.8 設定一致性門檻;minimize() 回傳通往 Y 的充分路徑。

Stata — 說明:QCA 於 R 進行

* read the sample file
import delimited "fsqca_sample.csv", clear case(preserve)
* Stata has no standard QCA command; inspect the calibrated memberships.
* Run the truth-table minimization in R (QCA package) as shown above.
list case A B C Y

Stata 無標準 QCA 指令;請使用 R QCA 套件(或 fsQCA 軟體)。

④ 假設與陷阱

校準是判斷

把原始數字變成隸屬度的錨點是實質選擇;不同錨點可能改變解。要用理論/外部知識證成,並證明結果對合理替代穩健,否則就是垃圾進、垃圾出。

有限多樣性/邏輯餘項

條件一多,多數邏輯可能的組合沒有案例(邏輯餘項)。你對這些沒觀察到的列做什麼假設,是一個反事實選擇,會決定保守/精簡/中間解,要說明你用了哪個、為什麼。

不是機率或效果量

一致性是集合關係的量,不是 p 值或效果量;QCA 不是為「推論到母體」設計的。門檻(一致性 0.8、頻次切點)是慣例;要做敏感度測試。因果主張仍靠理論與個案知識。

⑤ fsQCA 與機器學習:都在找「組合」

fsQCA 與機器學習都拒絕「單變數、可加」的觀點,它們都在找交互與組合。差別在精神:fsQCA 是少量案例上、理論驅動的集合邏輯;ML 是大量資料上、資料驅動的找型態。

規則/樹學習是 ML 表親

決策樹與規則探勘也輸出「若條件組合則結果」的句子,形式上接近 QCA 組態,但是為預測最佳化,不是為集合論充分性或可解讀性。

ML 可建議條件

在較大的資料上,ML 的特徵重要性或交互偵測可以建議候選條件,帶進理論導向的 QCA,但校準與因果解讀仍由分析者負責。

兩者都無法自動化的

挑出有意義的條件、校準它們、判斷哪些反事實站得住,都是實質判斷。QCA 的演算法與 ML 模型都給不了。

⑥ 如果……?等效性、不對稱與穩健性

反事實問題是 QCA 內建的:還有哪些配方能達到結果、沒觀察到的組合怎麼辦、換不同校準解還站得住嗎?

如果有好幾種配方?

等效性代表解可以有多條充分路徑,有些案例靠 A·B、有些靠 C·D。對每條路徑報一致性與(原始與獨有)覆蓋率,而不是硬選一個「冠軍」。

如果分析「結果不發生」?

因為因果不對稱,造成 ~Y 的配方不只是 Y 配方的否定,必須分開分析。某因子可能在「產生 Y」裡有份,卻與「~Y」無關。

如果校準改變?

用不同的錨點、一致性門檻與頻次切點重跑(SetMethods 支援)。在合理選擇下都成立的解才可信;輕輕動一下錨點就翻盤的,是假象。

受試者自身的實驗:測試藥與參考藥相等嗎?(生體可用率/生體相等性 BA/BE)

生體可用率(BA)問的是藥物進入血流的量有多少、速度有多快;生體相等性(BE)問的是測試劑型能不能取代參考劑型。我們讓同一批受試者交叉服用兩種劑型,再檢查「測試/參考」比值的 90% 信賴區間是否落在 80.00–125.00% 的相等性界限內。

工作流程

標準設計是隨機分組的 2×2 交叉試驗:每位受試者隨機分到 RT 或 TR 順序,先服一種劑型,經過足夠長的洗除期(washout)讓藥物排空,再服另一種。沿時間採血以取得每一期的 Cmax、Tmax 與 AUC。我們把 Cmax 與 AUC 取對數、配一個線性混合模型,將「測試/參考」幾何平均比值(GMR)反轉換回來,只有當其 90% CI 整段落在 80.00–125.00% 內,才判定為平均生體相等。

BA 量什麼

從濃度–時間曲線取:Cmax(最高濃度,反映速度)、Tmax(達峰時間)、AUC(總暴露量,反映程度)。BA 描述單一劑型的暴露;BE 則比較兩種。

為何用交叉

因為每個人當自己的對照,受試者間的變異被消掉,比較發生在同一個身體內。這讓 2×2 交叉成為本工具箱中最乾淨的因果對比:一個貨真價實的「受試者內」隨機實驗。

80–125% 規則

相等性界限 80.00–125.00% 在對數尺度上是對稱的(0.80 = 1/1.25)。平均生體相等要求 GMR 的整段 90% CI,Cmax 與 AUC 都要,落在這個帶內。

看專有名詞解釋

幾何平均比值(GMR) geometric mean ratio

因為 Cmax、AUC 這類藥動指標右偏、大致呈對數常態,我們在對數尺度上比較它們。GMR 是測試劑型的幾何平均除以參考劑型的幾何平均,等價於對數平均差的反轉換。GMR = 1.00 表示平均暴露相同;1.10 表示測試平均多出 10%。BE 以 GMR 而非算術平均比值來判定,正是因為對數尺度才是這些資料對稱之處,也是 80–125% 界限變得對稱之處。

洗除期 washout

兩個給藥期之間的間隔,要長到(通常 ≥ 5 個消除半衰期)第一種劑型在第二種給藥前基本排空。洗除期太短會讓藥物殘留到下一期,殘留效應(carryover),使受試者內的比較產生偏誤。

平均生體相等性(ABE) average bioequivalence

預設的法規標準:族群平均暴露的相等性,當 GMR 的 90% CI 落在 80.00–125.00% 內即成立。它不處理每個人是否反應一致(那是個體 BE),也不處理變異是否相符(族群 BE)。

互動式 BE:拖動真實 GMR,看判定結果

拖動滑桿設定真實的測試/參考比值(GMR)。圖會把估計 GMR 的 90% 信賴區間畫在 80.00–125.00% 的生體相等帶上,只有當整段 CI 都在帶內時才判定 PASS。注意:即使點估計接近 1.00,CI 太寬仍會失敗;比值漂向邊緣時,只要 CI 探出去就失敗。

陰影帶是 80.00–125.00% 的生體相等性界限;點與鬚是 GMR 及其 90% 信賴區間。只有整段 90% CI 都落在帶內,才能判定生體相等。合成教學資料。

資料分析:跑一次完整的平均生體相等性檢定

步驟

(1) 對每個受試者×期別的濃度–時間曲線做非房室分析(NCA),取出 Cmax 與 AUC。(2) 兩個指標皆取對數。(3) 配一個線性混合模型,以順序、期別、處置為固定效果,subject(sequence) 為隨機效果。(4) 對處置差求 90% CI,再反轉換回 GMR 尺度。(5) 與 80.00–125.00% 比較,Cmax 與 AUC 都要通過。


程式(SAS · R · Stata):平均生體相等性(2x2 交叉設計)

出處 — SAS 段落為 PROC MIXED 於 2x2 交叉設計的標準寫法(class subject sequence period treatment;random subject(sequence);estimate ... / cl alpha=0.10),即 FDA「Statistical Approaches to Establishing Bioequivalence」統計指引附錄所示範的程式碼,另見 SAS/STAT PROC MIXED 官方手冊;R 段使用 nlme 套件的 lme() 與 intervals(level=0.90),用法同 nlme 官方參考手冊;Stata 段使用官方 mixed 與 lincom(Stata Multilevel Mixed-Effects 手冊)。80-125% 界限依 FDA 生體相等性指引。

這是可直接在可下載的 babe_sample.csv 上完整執行的程式(欄位:subject, sequence, period, treatment, auc, cmax)。

SAS — 對 log(AUC) 跑 PROC MIXED

/* read the sample file */
proc import datafile="babe_sample.csv" out=d dbms=csv replace;
    getnames=yes;
run;
data d; set d; logauc = log(auc); run;
/* mixed model: fixed sequence period treatment, random subject(sequence) */
proc mixed data=d;
    class subject sequence period treatment;
    model logauc = sequence period treatment / ddfm=satterth;
    random subject(sequence);
    estimate "T vs R" treatment 1 -1 / cl alpha=0.10;
run;
/* exponentiate the estimate & 90% CL to get the ratio; check 0.80-1.25 */

PROC MIXED 為 FDA 標準擬合;對 90% 信賴界限取指數即得比值界限。

R — nlme::lme,反轉換為比值

# read the sample file
d <- read.csv("babe_sample.csv")
library(nlme)
d$logauc <- log(d$auc)
# mixed model with random subject within sequence
m <- lme(logauc ~ sequence + period + treatment,
         random = ~ 1 | subject, data = d)
ci <- intervals(m, level = 0.90, which = "fixed")$fixed
# the treatment row is the log Test/Reference difference
tr <- ci[grep("treatment", rownames(ci)), ]
# back-transform to ratio and 90% CI; BE if within 0.80-1.25
print(exp(tr))
# PowerTOST provides power/sample-size for this TOST design

對 90% 信賴區間取 exp() 得比值;落在 80-125% 內即判定生體相等。

Stata — 對 log(AUC) 跑 mixed

* read the sample file
import delimited "babe_sample.csv", clear case(preserve)
gen logauc = log(auc)
* mixed model: random intercept for subject
mixed logauc i.sequence i.period i.treatment || subject:, ///
    reml dfmethod(satterthwaite)
* 90% CI for the treatment effect, then exponentiate to the ratio
lincom _b[2.treatment], level(90)
display exp(r(estimate)), exp(r(lb)), exp(r(ub))

mixed 重現法規擬合;對 90% lincom 信賴區間取 exp() 得比值界限。

需要哪些前提(以及界限何時放寬)

充分洗除期,無殘留

洗除期必須在第二期前清掉第一種藥,否則殘留藥物會延續汙染受試者內的對比。順序效果顯著就是殘留效應(或真正的「順序×劑型」交互作用)存在的警訊。

無期別或順序效果

模型假設期別與順序在(對數尺度上)加法地平移暴露,且可與處置分離。若有強烈的期別效果或「順序×處置」交互作用,簡單的 ABE 估計可能誤導,要檢視這些項,別只讀 GMR。

對數常態 PK 與受試者內設計

Cmax 與 AUC 假設為對數常態(故取對數、用幾何平均)。交叉設計仰賴受試者內比較,因此每位受試者各期須處於可比的生理狀態並完成兩期,退出會侵蝕受試者內的優勢。

高變異藥物 → 比例放寬

當受試者內 CV 超過約 30%,固定的 80–125% 界限即使對真正相等的產品也幾乎不可能達到。參考比例放寬 ABE(RSABE)會依參考藥的受試者內變異(由重複設計估得)來放寬界限。

窄治療指數 → 收緊

對窄治療指數(NTI)藥物,暴露的小幅變化在臨床上就有意義,主管機關會收緊而非放寬,例如可收窄到約 90.00–111.11% 的比例界限,並常附加受試者內變異的比較。

足夠受試者與正確交叉

90% CI 必須精準到能塞進帶內,這需要對該藥變異有足夠檢定力的樣本。隨機的順序分派與平衡的 2×2(或重複)設計,正是支撐「因果、受試者內」詮釋的依據。

建模與機器學習在 BA/BE 的交會處

核心 BE 檢定是一個小型、規格嚴謹的實驗,中心地帶沒什麼讓 ML 發揮的空間。動作發生在邊緣:預測暴露、自動化曲線分析、在實際試驗前先模擬。也要老實說清楚:這些做法當中,哪些是主管機關目前已經接受的。

族群藥動/模型導向 BE

非線性混合效果(popPK)模型把跨受試者的稀疏資料匯整,估計暴露與其變異,對設計試驗有用,且日益用於「模型導向」作法,補充、或(在有限情形下)替代傳統 BE 臂。

NCA 自動化

擷取 Cmax/Tmax/AUC 與選取排除相是重複且規則化的工作;管線(與 ML 輔助的曲線品管)可標準化峰值偵測、lambda-z 選取與離群標記,降低不同分析者對 BE 檢定輸入的變異。

虛擬 BE/PBPK 模擬

生理基礎藥動(PBPK)與虛擬 BE 模擬可在任何給藥前預測兩劑型是否會通過,對排序與生體豁免(biowaiver)很有價值。法規接受度確實存在,但逐案審查、仍在成長;把模擬當作要論證的證據,而非自動通過。

如果……改變判定的邊角情況

80–125% 規則是預設、不是全貌。三個常見的「如果」會改變界限、或改變你必須證明的內容。

如果藥物高度變異?

若受試者內 CV 很大(> 約 30%),固定帶即使對相等產品也搆不到。改採重複設計與參考比例放寬 ABE(RSABE),依參考藥本身的變異按比例放寬界限。

如果是窄治療指數藥物?

反向操作:對 NTI 藥物,界限要收緊(例如收向約 90.00–111.11%),且通常還須證明測試藥的受試者內變異不差於參考藥。這裡的相等是更高、而非更低的門檻。

如果 Cmax 過、AUC 沒過?

那麼產品不具生體相等性。BE 要求速度指標(Cmax)與程度指標(AUC)兩者都落在界限內,一個過救不了另一個沒過。每個指標各以自己的 90% CI 判定。

濕式實驗:把「因」造出來,再看「果」

濕式實驗是觀察性因果推論的「實驗版互補」:不是在雜亂的人類資料裡硬校正混淆,而是直接到實驗檯或動物身上刻意介入,敲除一個基因、滴定劑量、把動物隨機分派到處理組,再讀出你量得到的機制反應。好處是內部效度極高(因是你造的,混淆被設計掉了)並能直接看到機制;代價是對人類的可轉移性不確定。它真正的威力在於三角驗證:當實驗檯結果與流行病學估計各自的弱點完全不同、卻指向同一方向時,因果主張會大大加強。

工作流程

挑一個可操弄的因(一個基因、一種化合物、一個劑量);把實驗單位(細胞、培養皿、動物)隨機分派並設盲,使各組僅在介入上不同;施加分級劑量;量測機制與表型結果;再用 ANOVA/迴歸與劑量反應曲線分析,並重複驗證。買到因果主張的是「設計」,不是統計。

基因操弄

敲除/敲入(CRISPR、條件型等位基因)把候選的因拿掉或裝上,再看表型是否隨之改變。這是在分子層級直接做「必要性」與「充分性」檢驗。

細胞株劑量反應

用分級濃度處理細胞,配出劑量反應曲線(EC50/IC50)。一條單調、可重現的曲線,是「暴露驅動讀數」的有力機制證據。

隨機化動物模型

把動物隨機分派到處理組與對照組,在設盲下量測結果,這是在整個生物體上做的真正實驗,銜接分子機制與生理終點。

看專有名詞解釋

內部效度 vs 外部效度 internal vs external validity

內部效度=在這個實驗內部,介入是否真的造成了量到的改變(沒有混淆、沒有偏誤)?隨機分派、設盲與對照讓濕式實驗的內部效度非常高。外部效度=那個效果是否搬得到人類與真實世界的劑量?這正是實驗檯研究最弱的地方,所以它要與觀察性證據搭配,而不是單獨採信。

三角驗證 triangulation

把「關鍵偏誤互不相關」的不同設計的估計合起來看,例如隨機化實驗檯實驗(內部效度強、可轉移性弱)與觀察性人類研究(剛好相反)。若兩者一致,就沒有單一共同偏誤能同時解釋它們,因果結論因而更可信(Lawlor、Tilling & Davey Smith 2016)。

互動:隨機實驗貼著真值,觀察曲線卻彎掉

學一條劑量反應有兩種方式。隨機化的濕式實驗(綠)以隨機方式指派劑量,所以劑量與其他一切無關,它估出的曲線貼在真實劑量反應上。觀察性關聯(琥珀)只是記錄各單位「剛好」拿到的劑量,而一個隱藏因子同時推動所選劑量與結果。拉動滑桿替觀察資料加入混淆,只有琥珀曲線會偏離真值,實驗那條從不移動。

綠=隨機分派的實驗劑量反應(真值);琥珀=被混淆的觀察性關聯。只有觀察曲線會隨混淆變強而偏;實驗始終貼著真值。合成教學資料。

資料分析:隨機分派、設盲、配劑量反應、重複

步驟

(1)把實驗單位隨機分派到劑量/基因型組,使介入與混淆獨立;(2)對操作與量測設盲以去除期望偏誤;(3)施加分級劑量並配劑量反應曲線(EC50);(4)用 ANOVA/迴歸檢驗組間差異(單位巢套於批次或同窩時用混合模型);(5)跨獨立批次重複,單次實驗是一個結果,重複才是證據。


程式(SAS · R · Stata):劑量-反應曲線(四參數邏輯斯)

出處 — R 段落即 drc 套件官方示範的標準流程:drm(response ~ dose, fct = LL.4()) 擬合四參數對數邏輯斯、summary() 看參數、ED(m, 50) 求 EC50、plot(m, broken = TRUE, type = "all") 畫曲線;呼叫方式同 drc 套件參考手冊與 Ritz, Baty, Streibig & Gerhard 2015「Dose-Response Analysis Using R」(PLoS ONE,該套件的軟體論文,文中即提供此程式碼)。SAS 的 PROC NLIN 與 Stata 的 nl 為同一四參數邏輯斯的對應寫法(見各自官方手冊)。

這是可直接在可下載的 wetlab_sample.csv 上完整執行的程式(欄位:well, dose, response, batch)。

SAS — PROC NLIN 四參數邏輯斯

/* read the sample file */
proc import datafile="wetlab_sample.csv" out=d dbms=csv replace;
    getnames=yes;
run;
/* 4-parameter logistic: b=slope, c=lower, e=upper, ec50 */
proc nlin data=d;
    parms b=1 c=0 e=100 ec50=10;
    model response = c + (e - c) / (1 + (dose/ec50)**b);
    output out=fit predicted=phat;
run;
/* ec50 is reported directly in the parameter estimates */

PROC NLIN 擬合相同的四參數邏輯斯;ec50 參數即 EC50 估計。

R — drc::drm() LL.4()

# read the sample file
d <- read.csv("wetlab_sample.csv")
library(drc)
# 4-parameter log-logistic dose-response model
m <- drm(response ~ dose, data = d, fct = LL.4())
print(summary(m))
# EC50 (effective dose for 50% response)
print(ED(m, 50))
# plot the fitted curve
plot(m, broken = TRUE, type = "all")

drm() 搭配 LL.4() 擬合四參數模型;ED(m, 50) 回傳 EC50 與其標準誤。

Stata — nl 四參數邏輯斯

* read the sample file
import delimited "wetlab_sample.csv", clear case(preserve)
* 4-parameter logistic; {ec50} is the EC50 parameter
nl (response = {c} + ({e} - {c}) / (1 + (dose/{ec50})^{b})), ///
    initial(b 1 c 0 e 100 ec50 10)
* inspect the fitted curve against the data
predict phat
twoway (scatter response dose) (line phat dose, sort)

nl 擬合相同的四參數模型;{ec50} 估計即 EC50。

這個實驗可不可信?三道效度提問

濕式實驗的證據好不好,取決於三種效度。內部效度通常因設計而強;難的是模型是否代表人類的暴露(構念),以及效果在真實世界劑量下能否搬到人身上(外部)。

① 內部效度,通常很強

隨機分派、設盲與同期對照,意味著組間任何差異都來自介入、而非混淆。要檢查的威脅:隨機化失敗、量測未設盲、偽重複(把子樣本當成獨立)、以及把批次效應誤當成處理效應。

② 構念效度,模型代表得了人類暴露嗎?

敲除是徹底、終生的喪失;人類的暴露可能是部分且短暫的。細胞株(已永生化或源自癌細胞)的行為未必像人類原代組織。要問:被操弄的因與量到的讀數,是否真的對應到你關心的人類暴露與結果。

③ 外部效度,搬得到人身上嗎?

在培養皿裡有效的劑量常是超生理的;物種在代謝與生理上不同;受控的實驗檯環境抹除了真實世界的異質性。一個乾淨的實驗檯結果是「關於人類的假說」,不是結論,要靠與人類證據三角驗證來確認。

用 AI 強化:表型判讀、篩選分流、與電腦預篩

機器學習不取代濕式實驗的實驗邏輯,買到因果的仍是隨機化。它改變的是通量與量測:從影像與體學讀出表型、分流哪些條件值得做完整試驗、用電腦預篩化合物讓實驗檯聚焦最有希望的候選。每一項都在幫忙產生假說、排出優先順序,但沒有一項能確認假說。

① 影像/體學表型判讀

深度模型能從顯微影像與體學評分細微的形態或分子表型,比人工評分更快、更可重現,提供敏感且無偏的結果量測。限制:學出來的表型只和它背後的標註與生物學一樣可靠,要對照金標準驗證。

② 高內涵篩選分流

在大規模篩選中,ML 把孔位/條件排序,讓稀缺的實驗檯資源用在最有希望的命中、並濾掉明顯偽影。限制:這是排序、不是證明,每個被 ML 標出的命中仍需隨機化的確認實驗,且排序可能繼承篩選特有的批次偏誤。

③ 電腦端預篩

以結構與 ML 為基礎的模型預測結合、毒性或活性,在動手實驗前先縮小化學或基因空間,省試劑與時間。限制:預測是相關性的、且只和訓練化學一樣好,它建議「該測什麼」,永遠不取代濕式實驗的讀數。

如果…?當實驗檯結果碰上現實

一個乾淨的實驗精準回答一個問題,卻沒回答它對人類是否重要。三個「如果」說明為何實驗檯結果只是三角的一條邊、而非全部答案,以及當它與流行病學不一致時該怎麼讀。

如果動物模型搬不過來?

物種在代謝、生理與疾病機制上不同,所以在小鼠身上的效果在人類可能根本不存在。別丟掉實驗,把它當成「可能機制」的證據,並依該通路在物種間的保守程度加權,再決定在人類身上採取行動。

如果劑量是超生理的?

如果效果只在遠超任何真實人類暴露的濃度下才出現,那可能是毒理學偽影、而非相關的因果效果。確認有效劑量與人類可達的水準重疊,並去讀劑量反應曲線的低劑量端,而不是只看最大效果。

如果它與流行病學不一致?

不一致是有資訊的、不是失敗。因為實驗檯與觀察性設計的弱點互不相關,衝突反而指向特定的元兇,可能是人類資料的殘餘混淆或選樣、也可能是模型可轉移性差。用三角驗證來化解:問「哪個設計的已知弱點最能解釋這個落差」,而不是直接宣布誰贏。

研究設計:資料允許什麼,設計就只能走到哪裡

在動手分析之前,一個研究只要做三個決定:問什麼、手上有什麼資料、能用什麼設計。這三件事不是三選一的清單,而是一條鏈:挑設計是下面流程的第 3 步,而第 3 步能走到哪裡,在第 2 步(資料裡有什麼)就已經被決定了。所以選資料庫和選設計放在同一頁,而且你每選一邊,另一邊就會跟著縮小範圍。

第 3、4 步是你真正要親手做的兩個決定,其餘都跟著它們走。點一個階段可以跳到對應段落。

因果推論的流程:一個公衛訊號,從無到有到結論

方法選單與「怎麼選」幫你挑單一設計。但真正的證據,是沿著一個訊號的生命週期把許多設計串起來,彼此補強弱點。這是端到端的流程圖,點任一設計即可打開。當「以不同方式出錯」的設計彼此收斂時,因果主張才可信,這就是三角驗證。

起點

一個公衛訊號

起於一筆自發通報、臨床醫師的直覺、例行監測的異常、或指引上的疑問:一個還沒人確認的「藥物→結果」關聯。

①

偵測與篩選(產生假說)

一次掃描「多種藥 × 多種結果」標出候選訊號,同時控制大量偽陽性。它們只標記、不確認。

②

界定問題、檢查資料

把訊號變成精確的目標試驗(PICO、納入條件、明確的時間零點、對照)。描述誰/何時,並處理缺失資料。你能跑哪個設計,由資料來源決定。

③

估計效果:挑一個控制混淆的設計

核心:依你的資料挑一個能去除混淆的設計。用「怎麼選」決策樹在下列家族間導航(準實驗 · 自身對照 · 主動對照新使用者 · 校正/PS/g-methods · 抽樣 · 代理)。

提醒:IV、RDD、MR 同一個引擎,都是「近似隨機」的外生變異。模糊 RDD 在切點附近就是一個局部 IV(門檻即工具),而 MR 是以遺傳變異為工具的 IV。識別邏輯相同,只是隨機的來源不同。

④

量化殘餘偏誤(敏感度分析)

沒有任何觀察性設計是不需要假設的。問:未測混淆、缺失、或殘餘偏誤要多強,才能推翻結果。

⑤

從外部佐證(機制與實驗)

引入「與觀察性資料以不同方式出錯」的證據:遺傳、實驗檯、或模型化。互不相關的偏誤仍一致,正是三角驗證的核心。

⑥

合成整體證據

用透明、可重現的流程把每篇可信研究合併成一個答案,並評整體證據確定性(GRADE)。

⑦

決策與外推

權衡效益與風險,把效果搬到你的族群,沒有對照時就借一個。

✔

因果結論 → 行動

當「以不同方式出錯」的設計彼此收斂,因果主張就可信,這是 Bradford-Hill 式、三角驗證的判斷,據以更新指引、仿單或政策。接著持續監測,循環回到 ①。

不是每個訊號都要跑完每一格,但藥物流行病學裡最強的因果結論,是跨這幾個階段三角驗證出來的,而不是單一研究就定案。

資料庫:你手上的資料庫,撐得起哪些設計

設計再好,也只能跟得上背後的資料。真實世界資料庫差別在類型(理賠、EHR、登錄、生物資料庫)、涵蓋(近乎全民 vs 抽樣樣本)、連結(死亡、住院、檢驗、基因)與長期可追溯性,這些特性決定你實際能跑工具箱裡哪些設計。先用下面的挑選器(以「藥物X 對某慢性病」的通用情境示範),再看「資料庫特性 → 設計強項」與藥物流行病學資料庫名錄(取自 AsPEN 網路)。

怎麼選資料庫:順著你的研究需求點下去

回答「你的研究最需要什麼」,它會落在本組常用的一個資料庫(健保、健保串癌登、健保串成人健檢、長庚 CGRD、診所病歷抄錄、HALST、TriNetX、Flatiron、Vestrum,以及 Aetion 平台),附一個藥物X 範例與能做的設計。完整總表、以及國際資料來源的延伸說明與參考文獻都在最後。

資料庫特性 → 撐得起哪些設計

近乎全民的全國理賠資料

全人口理賠(每筆給藥+診斷)最適合罕見結果與需要人內暴露變異的自身對照設計。撐得起:世代/病例對照(罕見事件)、SCCS 與 CCTC、PERR、序列試驗。弱點:檢驗值、臨床細節、處方的適應症。

含檢驗值與診斷的 EHR

電子病歷帶檢驗值、嚴重度與更豐富的診斷。撐得起:校正適應症混淆、主動對照新使用者(ACNU)、中介分析(有量到的中介/生物標記 M)。弱點:跨院完整度、樣本代表性。

長期可追溯

能追蹤成員多年(如達約 20 年)的資料庫,支援新使用者與盛行新使用者(PNU)設計、複製-設限-加權的持續策略、與長期結果。弱點:離開資料庫者的流失。

連結死亡與登錄

連結死亡與疾病登錄能做存活結果(存活型 RDD、CCW)與結果為死亡時的事件相依觀察期 SCCS。弱點:除非也連藥局,否則門診用藥細節有限。

生物資料庫/基因

把基因連到 EHR 的生物資料庫(如台灣人體生物資料庫、UK Biobank)能做工具變數/孟德爾隨機化,用基因變異當近似隨機的工具。弱點:自願者選擇、年齡範圍。

政策/資格切點

當資料庫記到政策日、給付門檻或年齡資格切點,就能借準隨機結構:RDD(明確切點)、DiD(政策+對照組)、ITS(單一序列的時間趨勢)。

不同領域、不同資料來源 → 不同方法

藥物流行病學不是唯一。每個領域都有自己的招牌資料,而那份資料決定了你「能不能」用某種設計,只有彙總銷售資料就只能做生態學/時間序列,可連結個人的登錄資料才打得開自身對照與目標試驗。一份(不完整的)對照:

藥物暴露/銷售(跨國)

「IQVIA MIDAS」(涵蓋約 90 國的藥品銷售與用量)與稽核/用量資料是彙總、非個人層級:你看得到賣了多少、看不到誰吃了。撐得起:藥物使用研究、政策對處方影響的 ITS、生態學/跨國比較。弱點:個人結果、混淆,沒有人層級的因果對比。

抗微生物藥物/感染科

「點盛行率調查(Global-PPS)」、「ESAC-Net」、WHO 的「GLASS」記錄抗生素使用與抗藥性。撐得起:PPS 設計本身(盛行率快照)、抗生素管理介入的 ITS、使用 vs 抗藥性的生態學。弱點:追蹤個人隨時間;單一病人暴露的因果效果。

腫瘤/癌症登錄

「SEER」、各國癌症登錄(如台灣癌症登錄),常與理賠連結(SEER-Medicare)。期別、組織型、存活很豐富。撐得起:存活世代、依期別/年齡治療門檻的 RDD、中介(路徑上的生物標記)。弱點:未連結時的門診用藥、領先時間/偵測偏誤。

全球疾病負擔/生態

「GBD(IHME)」、WHO 全球衛生觀測站彙總各國各年的死亡與風險因子估計。撐得起:政策的生態學/跨國 DiD 與 ITS、比較風險評估。弱點:生態謬誤,群體層級的關聯不必然適用於個人。

疫苗安全監測

「VAERS」與 WHO「VigiBase」(自發通報),以及可連結的「疫苗安全資料連結(VSD)」。撐得起:SCCS 與 TND、序列安全監測、對結果樹的 TreeScan;自發通報的不相稱性分析。弱點:自發系統的低報與被刺激通報。

重症/ICU 高解析

「MIMIC-IV」、「eICU」、AmsterdamUMCdb:密集、有時間戳的生命徵象、檢驗、點滴。撐得起:時變治療設計(g-methods/邊際結構模型、CCW)、對逐分鐘照護的目標試驗模擬。弱點:單中心選擇、時間零點沒處理好就落入不死時間陷阱。

母嬰/圍產

連結母親與嬰兒、跨懷孕的出生/圍產登錄。撐得起:手足對照(家庭內自身對照,控掉共享的基因/環境)、陰性對照、孕期暴露的目標試驗模擬。弱點:母體疾病本身的適應症混淆。

自發通報/安全訊號

「FAERS」(美國)與 WHO「VigiBase」,任何藥的自發不良事件通報。撐得起:產生假說的訊號偵測:不相稱性(ROR/PRR)、對事件階層的 TreeScan、處方瀑布的 PSSA。弱點:沒有分母、通報偏誤,訊號要在正規世代裡確認。

環境暴露

空污監測、氣象與區域層級暴露,依時間與地點連到健康紀錄。撐得起:急性效應的 ITS 與病例交叉(CCTC)、法規前後的 DiD、工具變數(風/逆溫)。弱點:暴露測量誤差、空間混淆。

藥物流行病學資料庫名錄(AsPEN 網路與夥伴)

整理自 AsPEN 資料庫名錄(phd-center.github.io/AsPEN)與 Sturkenboom & Schink(2020)。涵蓋與強項為約略值,供定位用。

資料庫類型 涵蓋強項/適合
東亞 · AsPEN 網路
台灣 健保資料庫 NHIRD理賠~2300萬,>99%,自 2000全國普查式理賠+現含檢驗/影像;罕見結果、自身對照、序列試驗
台灣 長庚 CGRD多院 EHR~150萬,自 2011檢驗值與臨床細節→適應症校正、ACNU、中介
台灣人體生物資料庫 TWB生物資料庫~20萬(目標百萬)基因+生活型態+臨床→工具變數/孟德爾隨機化
韓國 HIRA/NHIS-NHID理賠~5000萬,全國全國理賠;NHIS 另連投保與健檢
日本 NDB/JMDC理賠NDB ~1.2億;JMDC ~1350萬NDB 近全日本;JMDC 可追溯約 20 年→新使用者/PNU/持續策略
香港 CDARS全港 EHR~700萬公營,自 1995全港住院 EHR;臨床細節+連結
國際夥伴(對照基準)
英國 CPRD/THIN基層 EHRCPRD ~6000萬(連 HES、ONS)豐富基層+連結→多數設計,含 SCCS 範例
UK Biobank生物資料庫~50萬,40–69 歲基因+影像+EHR→工具變數/孟德爾隨機化
蘇格蘭 ISD全國 EHR~540萬,全人口給藥+住院+死亡→存活、自身對照
荷蘭 PHARMO多源連結~700萬(~40%),自 1999連結藥局+基層+住院→新使用者、主動對照
芬蘭 FinReg理賠+登錄~550萬,全人口,自 1972處方+出院+死因→長期、存活
澳洲 PBS/VLHD理賠(+連結)PBS 10% 抽樣;VLHD 全省補助給藥;VLHD 另連住院+死亡
美國 Medicare/Medicaid理賠Medicare 20%(~1300萬);Medicaid ~7000萬老年/低收入理賠;量大,但族群特定

跨區域網路(如 AsPEN, NeuroGEN)會把同一套協定跑在上述多個資料庫上再做合併分析,以單一資料庫的深度換取廣度、可推論性與可重複性。

怎麼選:同一個藥物X 問題,多種攻法

整個工具箱我們只問一個因果問題,用通用的說法就是藥物X 真的能改善某慢性病的結果嗎? 最理想的做法是隨機試驗,但我們常常做不到。於是多種真實世界證據/準實驗設計,各自從不同的地方「借」一點 近似隨機的變異來回答。這裡把它們並排,幫你挑出你的資料撐得起的那一個。

每一種設計,各自把「未校正偏誤」修回真值(按家族分組;中介分析還原真正的直接效果,可轉移性/外部對照還原目標族群的效果,最後一個家族則用遺傳工具與濕式實驗做三角驗證)

每種方法的真值在不同的尺度上(效果差、勝算比、率比、水準變化……),所以這裡把每個估計都除以 它自己的真值:1.0=完全命中。琥珀色=未校正比較(被混淆/不死時間/易感者耗竭從 1.0 帶偏); 青色=該方法校正後(貼回 1.0 附近)。長條依設計家族分組(借外生變異・借時間・自身對照・ 目標試驗模擬・主動對照新使用者・抽樣・代理/陰性對照・機制/中介),不同的還原真值方式,最後都落在 1.0 附近。

這些設計其實都一樣的地方

同一家族、同一套邏輯

  • 每一種都在「假裝」做隨機試驗。沒有一個真的隨機分派誰用藥,而是各自找到一段近似隨機的變異(或自身對照/抽樣的把戲)來頂替。
  • 每一種都押在一條不可檢驗的核心假設上。排除限制、連續性、平行趨勢、無同步混淆趨勢、無同時事件、 時間不變混淆、序列可交換、對照藥同適應症、時間條件可交換,每種設計都靠一條無法用資料證明的前提,外加可檢驗的佐證。所以每個方法都配一個 ④ 假設儀表板,一定要跑。
  • 多數都能用 ML 強化(⑤),且有好幾個現在真的會跑 scikit-learn。用彈性模型處理輔助部分、用交叉擬合當安全帶, IV、RDD、DiD、ITS、CC、SCCS、ACNU、PNU、MED、PS 都有真的 scikit-learn 示範;TiT 與 PERR 的文獻目前沒有現成的 AI 藥方。

另一類:用實驗與遺傳做三角驗證(wet lab + MR)

當觀察性校正還不夠時,用一個「以不同方式出錯」的方法佐證

上面的設計都是從觀察性資料裡擠出因果,因此共享同一個弱點,殘留的未測混淆。最有說服力的因果主張會做三角驗證,把偏誤互不相關的方法擺在一起,如果它們指向同一個答案,就不太可能只是同一個假象。觀察性工具箱之外,有兩個互補的類別:

孟德爾隨機化(MR):遺傳工具

MR 就是把工具變數的工具換成暴露的遺傳變異(或多基因分數)。等位基因在受孕時就分派(相對於後天生活型態/混淆近似隨機)且終生固定,所以一個有效的遺傳工具沒有混淆、也沒有反向因果。IV 的三條假設照舊,相關性(變異能預測暴露,小心弱工具)、獨立性(變異與結果之間沒有混淆)、排除限制(變異只透過暴露影響結果,最大威脅是多效性 pleiotropy)。雙樣本 MR 用 GWAS 彙總統計;敏感度工具有 MR-Egger、加權中位數、MR-PRESSO。工具:R TwoSampleMR、MendelianRandomization。

看 MR 完整 ①–⑥ 六個分頁 →

實驗室(wet lab)實驗:機制與操弄

實驗室與動物實驗能給觀察性資料給不了的東西,刻意操弄暴露、其餘維持不變(基因剔除/嵌入、細胞株劑量反應、隨機分派的動物模型)。它們建立機制與方向性,讓流行病學的關聯在生物學上可信,也能反駁一個被混淆的訊號。它們的限制正好和流行病學相反,內部效度高、但對人體與真實劑量的可轉移性不確定。正因如此兩者很搭:人體觀察估計與實驗機制若一致,就是「偏誤不重疊」的強證據。

看 Wet lab 完整 ①–⑥ 六個分頁 →

上面那張圖裡,MR 與 wet lab 是最後一個家族:未校正的觀察性關聯被混淆,而遺傳工具估計與實驗結果則從觀察性設計到不了的方向,把真值(≈ 1.0)還原回來。

比較數字之前:注意效果尺度(可塌縮性 collapsibility)

不是每種效果量都能直接相比

這些設計回報的效果在不同尺度上,而尺度本身會影響你該怎麼解讀「校正後」的估計。一個效果量若是可塌縮(collapsible), 代表全體(邊際)效果是各次群效果的合理平均,所以校正一個不是干擾因子的變項,目標不會改變。若是不可塌縮(non-collapsible), 則邊際與條件效果就算完全沒有混淆也會不同,數字會單純因為你多放了共變項而漂移。

  • 可塌縮,風險差/水準差(DiD、ITS)、風險比與率比(PERR、SCCS),以及 AFT 加速因子(RDD 存活 ③)。邊際數字所言即所是。
  • 不可塌縮,勝算比 OR(CC、TiT(估的是母體層級的因果勝算比)、Universal DiD,以及 CCTC,它原生估的是條件勝算比 OR,只有在罕見事件近似下才讀成率比)與風險比 HR(CCW 存活、RDD 經 Cox 的存活、ACNU/PNU)。校正後的 OR/HR 變動可能是尺度的假象,不一定代表混淆被修掉;HR 還內建隨時間的選擇(體質弱者先失敗)。
  • 實務建議,(1) 只比較同尺度的估計;上面那張「÷自己的真值」圖就是用正規化每個方法來迴避這問題。(2) 不要把「校正後 OR/HR 變了」直接讀成「混淆處理好了」,這個推論只對可塌縮的量成立。(3) 想要一個邊際、好解讀的存活(time-to-event)因果效果時,可塌縮的 AFT 加速因子很有吸引力(Crowther、Royston & Clements 2023),見 RDD ③。

同一個藥物X 問題,多種「借隨機」的方式(按家族)

方法 這個工具裡的藥物X 情境 「隨機」從哪借 最關鍵、不可檢驗的假設
家族 · 借外生變異(工具/斷點)
IV 近乎隨機的醫師用藥偏好,推了一部分病人去用藥物X 一個真正外生的工具(醫師偏好) 排除限制:偏好只透過「用藥物X」影響結果
RDD 藥物X 只在檢驗值超過門檻時才給付 分數上的明確門檻(檢驗值) 連續性:剛好門檻上下的人其他條件相同
家族 · 借時間(政策時點/前後趨勢)
DiD 某些醫院在某個時點把藥物X 納入常規 時間:導入在已知時點對部分醫院開啟 平行趨勢:沒政策時兩組會一起變
ITS 某體系在已知月份把藥物X 納入處方,逐月追蹤結果 時間:介入前趨勢外推當反事實 導入的同時沒有別的事也發生
PERR 病重者較常用藥物X;比較用 vs 未用者在用藥前後的事件率 同一群人「用藥前」的率比當混淆基準 混淆時間不變且乘法
TiT 藥物X 的使用率隨季逐漸上升,不同族群快慢不同 藥物X 使用率隨時間、跨層不同的趨勢 沒有與使用趨勢同步的未測混淆趨勢
家族 · 自身對照(同一個人前後比)
CCTC 同一人「急性事件前的危險窗」vs「更早的參考窗」,且暴露盛行率隨日曆時間漂移 同一人前後比+對照序列把暴露時間趨勢除掉 參考窗可交換、時間趨勢扣得對
SCCS 只用發生過事件的人,比較他們「用藥後危險窗」vs「自己其他時間」 條件在「人」,所有時間不變因子相消 事件不改變日後的暴露機率
家族 · 目標試驗模擬(持續/點治療策略)
CCW 比較動態策略:早用 vs 晚用藥物X(或持續 vs 停藥) 對齊時間零點+對人為設限做 IPCW(g-methods) 序列可交換,無未測的時變混淆
Seq 點決定(現在用藥物X vs 不用);每個資格月開一場模擬試驗,再合併 在每個資格時點模擬一場試驗、對齊時間零點 每場模擬試驗內的基線可交換
家族 · 主動對照新使用者世代(同適應症的對照藥)
ACNU 藥物X 的新使用者 vs 同類對照藥的新使用者(同適應症) 同適應症的主動對照+明確的新使用者時間零點 對照藥同適應症、且對該結果中性
PNU 把已用藥物X 一段時間的人(盛行使用者)依「距起始時間」對齊納回來 時間條件配對+時間條件傾向分數 時間條件可交換、且拿得到暴露起始史
家族 · 抽樣設計/預防效力(依結果或求醫檢驗者做有效率抽樣)
CC 找有事件的人(病例)vs 沒事件的人(對照),再回頭看用藥物X 史 依結果對「模擬目標試驗的世代」做有效率抽樣,再校正 對照代表來源族群;已測混淆校正
TND 求醫且接受檢驗的人之中:目標陽性為病例、陰性為對照,比兩者的藥物X 使用勝算 條件在「有來檢驗」這個選樣,陰性對照讓就醫傾向相對用藥物X 非差別 對照病症中性、檢驗準確、相同症狀下就醫無差別
家族 · 代理/陰性對照(近端因果)
NC/PCI 就醫傾向(未測)同時影響用藥物X 與結果;你有陰性對照結果(用藥前事件)與陰性對照暴露 一對陰性對照,未測混淆的代理(A 不影響 W、Z 不影響 Y) 陰性對照的「無因果」+混淆橋/完備性
家族 · 機制(接在上面任一設計之後的效果分解)
MED 已知有效果(藥物X → 結果);你還量了一個中介 M(生物標記),位在 A → M → Y 的路徑上 不借,中介分析不是控制混淆的設計,而是把已知效果做分解 無未測的 M–Y(+A–Y、A–M)混淆、且無暴露誘發的 M–Y 混淆,不可檢,隨機化 A 也換不到
家族 · 共變項校正/傾向分數/雙重穩健(已測共變項夠豐富)
PS 病重者較易用藥物X(適應症混淆);用已測共變項建「用藥機率」(傾向分數) 不借外生變異,在已測共變項上重建平衡(配對/IPTW/重疊權重) 無未測混淆+正性(重疊),傾向分數救不了沒量到的混淆
TMLE 同 PS 的情境,但你想更穩,同時配結果模型與傾向分數兩張網 同 PS(靠已測共變項);估計上用雙重穩健(AIPW/TMLE),其一對就不偏 無未測混淆+正性;且至少一個輔助模型正確(Super Learner 函式庫要夠)
家族 · 時變治療/g-methods(治療與混淆隨時間互相回饋)
G-methods 是否持續用藥逐期變動;時變的疾病狀態受過去用藥影響、又預測未來用藥與結果(用藥-疾病回饋) 不借外生變異,序列校正:標準化(g-formula)或反機率加權(MSM);不能直接「條件在 Lₜ」 序列可交換(無未測時變混淆)+每時點正性+模型正確
WCE 長期用藥物X(多劑、隨時間給);效果如何隨「用藥的時間與累積」變化(最近一劑 vs 很久以前的劑) 不借外生變異,把暴露史用「從資料學出的權重曲線」加權成摘要再估效果 暴露史量得準、時間窗夠長、風險模型形式正確,且最關鍵,無時變的適應症混淆
家族 · 訊號偵測(產生假說的篩檢,不是單一估計)
PSSA 用藥物X 後,是否更常開始用某種「標記藥」(處方瀑布)?只看在一個時窗內藥物X 與該藥都新起始的人 自身對照,時間不變混淆在個人內相消;只需用 SRnull 除掉日曆趨勢 瀑布方向合理、趨勢建模正確、新使用者、時間窗合適
TreeScan 用藥物X 對「一整棵分層的不良事件(ICD 樹)」做安全性篩檢,哪些結果節點的超額極端到不像「藥物X 沒作用」的世界 不估單一效果,用「打亂暴露標籤的排列虛無」當對照,掃描整棵樹找最極端節點(已控多重比較) 樹有意義、各節點基準為常數、無未建模混淆(否則排列虛無不對)
家族 · 可轉移性/外部對照(借外部資訊,再校正「誰不一樣」)
Transportability 藥物X 的效力是在某個族群的(隨機)研究裡量到的,但你的目標族群效果修飾子分布不同(例如更年長、共病更多) 不是用來校混淆,研究本身已無偏;借的是已測效果修飾子的分布,用來把效果加權/標準化到目標族群 條件可轉移性:兩族群間有差異的效果修飾子全部都測得到,且兩者分布有重疊
External control 單臂藥物X 研究(全部用藥、沒有同期對照);你借一個外部/歷史的未用藥世代當對照臂 借的是整個對照臂,再用標準化/傾向加權把外部對照校到試驗的共變項分布 扣掉已測共變項後外部對照可交換、無時代/來源漂移、結果定義一致,且有重疊
家族 · 借外生變異:MR(孟德爾隨機化)就是「以基因為工具」的 IV
MR 不用醫師偏好,而是用一個會提高暴露機率(或代理暴露)的遺傳變異當工具,問暴露本身是否影響結果 受孕時的隨機:等位基因相對於生活型態/混淆近似隨機分派且終生固定(以遺傳變異為工具的 IV) IV 三條,相關性、獨立性、排除限制(無多效性:變異只透過暴露影響結果)
家族 · 數位孿生(模型預測的對照軌跡)
Digital twin 用對照/歷史病人建預後模型,預測每位治療病人「未治療」的軌跡;效果=實際值減去預測的孿生 向預後模型借精準度/比較對象(PROCOVA 共變項,或合成對照臂),借的不是隨機 預後模型無偏、校準良好、可轉移到當前病人(它本身修不了未測混淆)

各需要什麼資料、答案是關於誰

方法 資料裡需要有什麼 答案是關於誰(估計目標)
家族 · 借外生變異
IV一個合格的工具變數(通常最難找)被工具推動的順從者 LATE
RDD一個帶明確資格規則的運行變數Sharp:斷點處 LATE;Fuzzy:斷點處順從者 LATE
家族 · 借時間(政策時點/前後趨勢)
DiD單位×期別的面板,含對照組介入社區的平均處置效果(ATT)
ITS一條序列、介入前後都有許多時間點該母體的水準與斜率變化
PERR分組的事前/事後期事件數與人時處置者的因果率比
TiT多期個體資料、罕見結果、夠強的使用趨勢母體層級的因果勝算比(≈相對風險)
家族 · 自身對照
CCTC急性事件+多時窗的短暫暴露紀錄;暴露有日曆時間趨勢個人內勝算比(已扣掉時間趨勢)
SCCS只要發生過事件的人;暴露有明確的危險時窗個人內的相對速率(IRR)
家族 · 目標試驗模擬
CCW個體層資料、時變的治療過程、事件時間持續/動態策略(早 vs 晚)的效果
Seq個體層資料、在多個時點陸續符合資格點治療決定的效果(跨試驗合併)
家族 · 主動對照新使用者世代
ACNU同一適應症兩種藥的新使用者世代,含共變項A 相對於主動對照藥 B 的效應
PNU含盛行使用者的世代,含距起始時間與起始史含盛行使用者族群中 A vs B 的率比
家族 · 抽樣設計/預防效力
CC病例+代表來源族群的對照,含暴露史勝算比(結果罕見時 ≈ 相對風險)
TND求醫且做了檢驗的人,含檢驗結果(目標陽/陰)與藥物X 使用史預防效力 = 1 − 勝算比
家族 · 代理/陰性對照(近端因果)
NC/PCI治療、結果、共變項+一個陰性對照結果(NCO)與一個陰性對照暴露(NCE)在未測混淆下的因果效應(用陰性對照對近端辨識)
家族 · 機制(分解)
MED治療 A、量在 A 之後 Y 之前的中介 M、結果 Y、共變項 X(每人一列)把總效果拆成自然直接 NDE + 自然間接 NIE,以及被中介比例
家族 · 共變項校正/傾向分數/雙重穩健
PS治療、結果、與一組夠豐富的已測共變項(每人一列)在已測共變項可交換下的平均處置效果(ATE/ATT/重疊族群)
TMLE同 PS(治療、結果、豐富共變項),適合搭機器學習輔助模型平均處置效果(半參數有效率、雙重穩健的估計)
家族 · 時變治療/g-methods
G-methods個體層、時變治療與時變共變項的縱貫資料、事件時間一個(持續/動態)治療策略的反事實效果
WCE計數過程(start, stop, event)格式、每區間記錄劑量的逐時暴露史一段暴露史(含時間形狀)對風險的效果,外加權重曲線
家族 · 訊號偵測(產生假說)
PSSA同一群人兩種藥的新起始日期,一段觀察窗校正趨勢後的「先後不對稱」比(aSR),作為 A→B 訊號
TreeScan暴露 vs 否,以及落在一棵階層樹上的多種結果(如 ICD 碼)不是單一效果,而是「哪些結果節點有訊號」(控制多重比較後)
家族 · 可轉移性/外部對照
Transportability研究的個體層資料(治療、結果、效果修飾子)+目標族群的效果修飾子分布目標族群裡的效果(用標準化/選樣反勝算加權)
External control一個治療的(單臂)世代+一個外部未治療世代,含共同的預後共變項試驗族群的治療效果(標準化/IPSW;貝氏動態借用)

決策樹:點一點,挑出最適合的設計

建構在藥物流行病學的「錨點(anchor)」取向上,把常見研究設計與本工具箱的方法(含中介分析、可轉移性與外部對照)合進同一棵可點擊的樹。順著你的研究情境一題一題點下去,最後會落在最適合的建議。✓=本工具箱已實作(可直接前往);↗=延伸設計,供參考。前三個錨點用來選單一研究的設計;第四個錨點(D · 證據錨定)高一層,適用於「答案主要來自別人已經做過的研究」:可以是把多篇合併(系統性回顧與統合分析、網路統合分析),也可以是借一篇補上你自己研究缺的那一塊(只有治療臂時借外部對照臂,或把結果轉移到你的族群)。其餘跨方法主題(因果機器學習、缺失資料、群組軌跡模型、量化偏誤分析、多準則決策分析、模糊集質性比較分析)屬於另一層、不在這棵樹上,請從方法下拉選單選取。

✓ 本工具箱已實作(可點擊前往) ↗ 其他延伸設計,供參考

鄰近取向:在因果推論「旁邊」,不在其中

本工具箱有幾個工具,並不是「從資料估計因果效果」的設計,它們做的是決策或製劑比對。它們不放進主要的因果選單、也不在上面那棵樹裡,但各自仍保有完整的 ①–⑥ 教學分頁,點下面任一個打開。(濕式實驗同樣不在樹上,但它的角色是三角驗證的夥伴,見上方 wet lab + MR 那一段。)

MCDA · 多準則決策分析

把多個衝突準則用權重彙整成可比較分數來排序選項的決策工具。

看完整 ①–⑥ 六個分頁 →

fsQCA · 模糊集質性比較分析

以集合論找「哪些條件組合對結果充分/必要」的組態分析。

看完整 ①–⑥ 六個分頁 →

BA/BE · 生體相等性

隨機 2×2 交叉的人體藥動試驗,比 Cmax/AUC 是否落在 80–125%。

看完整 ①–⑥ 六個分頁 →

RDD 的「局部隨機化」會不會其實就是 IV?

很好的直覺,而且大致上是的,尤其是模糊 RDD(fuzzy RDD)。在局部隨機化的講法裡, 「剛好落在門檻上方還是下方」在一個很窄的窗內被當成近似隨機分派, 這正是 IV 裡那個隨機工具 Z 扮演的角色。

在模糊 RDD 中,跨過門檻並不百分百決定處置,只是改變了拿到處置的機率。 這讓「是否跨過門檻」成為一個真正的工具變數:在局部滿足相關性與排除限制, 估計式就是一個只在門檻附近成立的 2SLS/IV。所以模糊 RDD 其實就是「把門檻當工具」的局部 IV。

真正的差別在於「隨機」是從哪裡借來的。IV 的工具可以來自任何地方、可能推動廣大的母體; RDD 的「工具」只有門檻這一個點,只在很薄的窗內近似隨機,所以答案天生是局部的。 而銳利 RDD(sharp RDD)比較不像 IV:那裡跨過門檻會百分百決定處置(沒有「順從者 vs 反向者」的第一階段), 所以更像門檻旁的一場小型隨機試驗,而不是 IV。

一句話總結

這裡每一種設計都在「假裝」做隨機試驗,各自從不同的地方借「可比性」,一個隨機推力或門檻(IV、RDD)、 政策時點或前期趨勢(DiD、ITS、PERR、TiT)、病人自己當對照(CCTC、SCCS)、模擬試驗裡對齊的時間零點 (CCW、Seq)、一個主動對照藥(ACNU、PNU),或依結果做有效率的抽樣(CC)。每種都依賴一條無法完全檢驗的 假設,所以一定要跑它的 ④ 儀表板。你手上有什麼,工具、門檻、對照組、時間序列、自身對照的時窗、 對照藥、用藥起始日,就決定你能用哪一種。而當兩三種不同設計都指向同一個答案時,你就能更有信心。

孟德爾隨機化:讓大自然替你做隨機試驗

我們想知道某個暴露(例如終生的 LDL 膽固醇)是否導致某疾病。要做一個從出生就隨機分配膽固醇的真實試驗是不可能的。但基因在受精時幾乎是隨機分發的,所以一個會把膽固醇往上推的遺傳變異,就像一台微型的天然隨機分配器。孟德爾隨機化(MR)把這類變異當成工具變數:若變異提高了暴露、又按比例提高了疾病,那就表示是暴露在發揮因果作用。

工作流程

挑選與暴露穩健相關的遺傳變異(SNP)→ 取得每個變異對暴露的效果(βX)與對結果的效果(βY),通常來自兩個大型 GWAS → 每個變異的比值 βY/βX 就是一個因果估計(Wald 比值)→ 用逆變異數加權(IVW)把它們合成一個數字 → 跑敏感度方法(MR-Egger、加權中位數)確認答案沒有被不符合假設的變異帶偏。

為什麼基因能當工具

你的基因型在受精時就固定、且在人群間大致隨機洗牌(孟德爾定律),所以它通常先於、也獨立於那些混淆一般研究的生活型態與疾病因素。這讓一個相關的變異成為可信的自然實驗。

一個變異 → 一個 Wald 比值

若一個變異把暴露提高 βX、把結果提高 βY,則暴露對結果的隱含因果效果就是比值 βY / βX。每個變異各給一個比值;有效的變異們應該彼此一致。

用 IVW 合併

把許多變異的 βY 對 βX 畫出來,這些點應落在一條過原點的直線上;它的斜率就是 IVW 因果估計。標準誤較小的變異拿到較大的權重。

看專有名詞解釋

多效性 horizontal pleiotropy

一個基因常常不只做一件事。水平多效性是指一個變異透過暴露以外的某條路徑影響結果,例如一個膽固醇變異同時獨立地影響發炎、而發炎本身又影響心臟病。這條額外路徑破壞了 MR 的關鍵「排除」規則:變異不再只透過暴露影響結果,於是它的 Wald 比值被汙染。在散佈圖上,有多效性的變異會偏離那條過原點的直線;若很多變異如此,IVW 斜率就有偏。MR-Egger 的處理方式是允許直線有不為 0 的截距,而這個不為 0 的截距本身就是「有多效性」的警訊。

互動式 MR:讀出因果斜率,再看多效性怎麼讓它偏掉

每個點是一個遺傳變異:水平位置是它把暴露提高多少(βX),垂直位置是它把結果提高多少(βY)。當工具有效時,這些點會沿著過原點的直線排好,而那條線的斜率就是因果效果(IVW 估計)。把選單切到「部分多效性」,會有幾個點偏離直線,它們透過第二條路徑推動結果,於是 IVW 斜率有偏;但 MR-Egger 允許直線不從原點出發,它不為 0 的截距就標記出多效性。

每個點是一個遺傳變異:x=它對暴露的效果、y=它對結果的效果。過原點直線的斜率即 IVW 因果估計;MR-Egger 截距不為 0 代表有多效性。合成教學資料。

資料分析:跑一次兩樣本 MR

步驟

兩樣本 MR 從兩個獨立的 GWAS 讀出兩個效果量。① 從暴露 GWAS 挑出與它穩健相關(達全基因組顯著)的變異,並做修剪使彼此不相關(LD clumping)。② 從結果 GWAS 取出同一批變異的效果。③ 調和,使兩邊效果都對應同一個等位基因(弄錯股向會悄悄翻轉正負號)。④ 算出每個 Wald 比值並以 IVW 合併。⑤ 再用 MR-Egger 與加權中位數重跑,並檢定 MR-Egger 截距是否有多效性。


程式(SAS · R · Stata):兩樣本孟德爾隨機化

出處 — R 使用 MendelianRandomization 套件的 mr_input() → mr_ivw()/mr_egger()/mr_plot(),呼叫方式同該套件官方 vignette(CRAN: package=MendelianRandomization)。

這是可直接在可下載的 mr_sample.csv 上完整執行的程式(欄位:snp, beta_exp, se_exp, beta_out, se_out, eaf)。

SAS — 以加權 PROC REG 做 IVW

/* IVW = weighted regression of beta_out on beta_exp through origin, w=1/se_out^2 */
proc import datafile="mr_sample.csv" out=d dbms=csv replace;
    getnames=yes;
run;
data d; set d; w = 1/(se_out*se_out); run;
proc reg data=d;
    weight w;
    model beta_out = beta_exp / noint;
run;
quit;

無截距加權迴歸的斜率就是 IVW 因果估計值;加入截距就是 MR-Egger。

R — MendelianRandomization

# IVW and MR-Egger from summary statistics, plus scatter plot
library(MendelianRandomization)
d <- read.csv("mr_sample.csv")
obj <- mr_input(bx = d$beta_exp, bxse = d$se_exp,
               by = d$beta_out, byse = d$se_out)
mr_ivw(obj)
mr_egger(obj)
mr_plot(obj)

mr_input() 整理摘要統計量;mr_ivw() 與 mr_egger() 給出因果估計值;mr_plot() 繪製 SNP 散布圖。

Stata — 以加權 regress 做 IVW

* IVW = weighted regression through the origin, analytic weights 1/se_out^2
import delimited "mr_sample.csv", clear case(preserve)
gen w = 1/(se_out^2)
regress beta_out beta_exp [aw=w], noconstant
* add a constant for MR-Egger: regress beta_out beta_exp [aw=w]

加上分析權重與 noconstant 的 regress 就能重現 IVW 斜率;若有安裝 mrrobust 套件,也可以用 mregger。

這個 MR 可不可信?工具三條件,加上敏感度工具

MR 就是工具變數,所以它依賴同樣的三條規則,相關性、獨立性、排除限制,只是用遺傳的語言來讀。只有第一條能完全由資料證明,其餘兩條靠敏感度分析來防守。

① 相關性,當心弱工具

變異必須確實能撼動暴露。弱工具(F 統計量偏低,經驗法則 F < 10)會把兩樣本 MR 拉向虛無、並放大變異。請使用達全基因組顯著的變異,並報告 F 統計量或解釋的變異比例。

② 獨立性,族群分層

變異必須獨立於暴露–結果關係的干擾因子。主要威脅是族群分層:祖源差異讓基因型與疾病一起群聚,偽造出一個遺傳效果。請在單一祖源內分析,並校正遺傳主成分。

③ 排除限制,多效性與檢測法

變異只能透過暴露影響結果,水平多效性會違反它。沒有檢定能完全證明,但 MR-Egger(截距不為 0 即標記)、加權中位數(過半權重來自好工具時仍有效)與 MR-PRESSO(偵測並剔除離群變異)三者一起對答案做壓力測試。

機器學習與 MR 的交會處(以及尚未交會處)

MR 的可信度來自設計,基因是大自然的隨機分配器,而不是來自任何花俏的估計器。機器學習多半出現在邊緣:挑選與清理工具、以及找出離群點。它們都救不了壞掉的排除假設,所以請把這些當成整理工作,而不是因果魔法。

工具挑選/降維

面對數千個候選變異與數百萬個相關,懲罰迴歸(LASSO)與相關方法可幫忙挑出穩定、近乎獨立的工具集合,或把許多弱變異彙總起來。有用,但在「用來檢定的同一份資料」上做挑選會引入勝者詛咒偏誤。

MR-PRESSO,離群偵測

MR-PRESSO 是 MR 中最成熟的「資料驅動」工具:它標記出 Wald 比值異常(很可能有多效性)的個別變異、移除它們、再重新估計。它是有用的敏感度檢查,但「剔點」本身就是一種建模選擇,過度使用反而會使結果有偏。

一個重要提醒

目前沒有任何成熟的 ML 方法能把無效工具變成有效工具。彈性模型能精修工具挑選、找出離群,但因果識別仍完全靠相關性、獨立性與排除限制。一個很會預測結果的模型,不等於一個因果效果。

「如果……」對一個 MR 研究做壓力測試

MR 的招牌數字,好不好全看它的假設。我們逐一走過最常推翻 MR 結論的三種失敗,以及對應的防守設計。

如果有多效性?

若變異透過第二條路徑影響到結果,IVW 就有偏、散佈點會偏離過原點的直線。把 IVW 與 MR-Egger(看它的截距)、加權中位數與 MR-PRESSO 互相比較:若大致一致,結論就穩健;若彼此分歧,就別信 IVW。

如果工具很弱?

低 F 的工具會把兩樣本估計收向 0、並把區間拉寬,於是一個真實效果可能看起來像虛無。請報告 F 統計量、優先使用達全基因組顯著的變異,並盡量在獨立樣本交叉驗證,以評估勝者詛咒與弱工具偏誤。

如果因果是反向的?

也許是疾病改變了暴露,而非反過來。雙向 MR 把暴露與結果對調再跑一次分析,而 Steiger 檢定檢查每個變異對暴露的解釋是否多於對結果的解釋,兩者一起幫忙釘住箭頭的方向。

數位孿生:為每位病人預測一條「對照」軌跡

數位孿生是一個預後模型,用豐富的歷史與對照臂資料訓練,預測每位病人在對照(不治療)下的結果會是多少。接著把治療效果讀成實際值減去預測的孿生值。這條孿生可以當作預後共變項調整(PROCOVA)、外部/合成對照臂,或用來跑虛擬(in-silico)試驗。重點是:孿生本身不消除任何混淆,它借的是精準度與一個比較對象,其有效性完全取決於預後模型是否無偏、且可轉移到你套用的病人身上。

工作流程

在對照/歷史病人上訓練一個預後模型,用基線共變項預測未治療結果 Ŷ₀。為每位當前病人產生孿生 Ŷ₀。接著或者 (a) 把實際 Y 與 Ŷ₀ 對比來估效果,或者 (b) 把 Ŷ₀ 當成單一、強力的共變項帶入(PROCOVA),以縮小隨機對比的變異。最後,先在留存的對照資料上驗證孿生的校準,再信任它。

① 預後共變項調整(PROCOVA)

在隨機試驗裡,把數位孿生預測 Ŷ₀ 當成事先指定的共變項加入。隨機化本身已保證無偏;孿生只是吸收預後變異,於是同一個效果能用更窄的區間估出(同樣檢力下樣本更少)。

② 外部/合成對照臂

當同期對照稀缺(罕病、腫瘤),預測的孿生充當以模型為基礎的對照臂,把每位治療病人對比到自己預測的未治療軌跡。此時孿生取代了隨機化,因此預後模型必須獨自承擔可比性的全部重擔。

③ 虛擬(in-silico)試驗

為整個虛擬世代產生孿生,可模擬未治療軌跡、壓力測試設計、並在真實試驗之前或同時預測結果,對規劃很有用,但好壞完全取決於背後的生成式預後模型。

看專有名詞解釋

數位孿生 digital twin

針對個別病人、由模型預測的反事實對照:在不治療下、依其基線特徵預期會有的軌跡或結果。它是預測而非觀測,因此會繼承產生它的模型的一切偏誤。

預後分數 prognostic score

基線共變項的一個摘要 Ŷ₀,用來預測未治療結果。對它做調整(PROCOVA)是傾向分數的「結果模型版孿生」:在隨機試驗能提升精準度、在觀察性研究可支援標準化,但本身並不控制混淆。

互動:看孿生模型有偏時,估計效果如何漂走

這裡是某位病人的實際(接受治療)軌跡,與模型預測的數位孿生對照軌跡。兩者間的垂直落差就是估計的治療效果。拖動滑桿讓孿生模型更有偏或更無偏:當孿生偏離真實對照軌跡時,估計效果就偏離真值,即使實際治療完全沒變。

青色=病人實際(接受治療)的結果隨時間變化;灰色虛線=數位孿生預測的「對照」軌跡;兩者落差即估計的治療效果。模型一旦有偏,估計就算治療沒變也會偏離真值。合成教學資料。

資料分析:建立孿生,再做對比或調整

步驟

(1)在對照/歷史病人上,為未治療結果訓練一個預後模型。(2)用基線共變項為每位當前病人預測孿生 Ŷ₀。(3)把效果估成治療組的 mean(實際 − Ŷ₀),或把 Ŷ₀ 當共變項帶入(PROCOVA 式的 g-computation)。(4)信任這個對比前,先在留存的對照資料上驗證 Ŷ₀ 的校準。


程式(SAS · R · Stata):數位孿生/預後分數校正對照

這是可直接在可下載的 dt_sample.csv 上完整執行的程式(欄位:pid, source, arm, x1, x2, x3, y)。

SAS — 預後模型後做 ANCOVA

/* read the sample file */
proc import datafile="dt_sample.csv" out=d dbms=csv replace;
    getnames=yes;
run;
/* fit prognostic model on historical controls, score everyone */
proc reg data=d outest=b noprint;
    where source="historical";
    model y = x1 x2 x3;
run;
proc score data=d score=b out=sc type=parms predict; var x1 x2 x3; run;
/* ANCOVA on the concurrent trial using the prognostic score */
proc glm data=sc;
    where source="trial";
    model y = arm MODEL1 / solution;
run;
quit;

PROC REG 建立預後分數;PROC GLM 對試驗臂做 ANCOVA。

R — lm() + predict() ANCOVA

# read the sample file
d <- read.csv("dt_sample.csv")
# prognostic model of control outcome on historical controls
pm <- lm(y ~ x1 + x2 + x3, data = subset(d, source == "historical"))
# prognostic score = predicted control outcome for everyone
d$progscore <- predict(pm, newdata = d)
# ANCOVA on the concurrent trial, adjusting for the prognostic score
tr <- subset(d, source == "trial")
fit <- lm(y ~ arm + progscore, data = tr)
print(summary(fit))
print(confint(fit, "arm"))

預後分數在不揭盲同期結果的情況下提升治療估計精準度。

Stata — regress + predict

* read the sample file
import delimited "dt_sample.csv", clear case(preserve)
* prognostic model on historical controls, then score everyone
regress y x1 x2 x3 if source=="historical"
predict progscore, xb
* ANCOVA on the concurrent trial
regress y arm progscore if source=="trial"

predict, xb 產生預後分數;regress 給出校正後的臂效果。

這條孿生可不可信?三道體檢

① 無偏且校準良好

預後模型必須在整個共變項範圍內無系統性誤差地預測未治療結果:在留存對照上,預測 Ŷ₀ 應平均、且在每個水準都與實際對照結果相符。校準不良的孿生會讓所有以它為基礎的對比都偏。

② 可轉移到當前族群

模型通常是在不同年代、場域或族群上訓練的。若標準照護、病例組成或量測自訓練後已改變,Ŷ₀ 就不再描述你的病人未治療軌跡,把它當對照臂會重新落入歷史對照的經典陷阱。

③ 它修不了未測混淆

當孿生取代同期對照時,有效性完全押在預後模型上,它不控制任何未測混淆,且暴露於迴歸到平均與模型設定錯誤。若僅作為隨機試驗中的精準度調整(PROCOVA),這些風險就溫和得多。

用 AI 強化:孿生本來就是機器學習的產物

數位孿生本身就是機器學習方法:它的全部價值來自一個能精準預測未治療結果的預後模型。模型越豐富、校準越好,孿生能借的精準度(或可比性)就越多,但彈性同時放大了過擬合與資料漂移的風險。

① 彈性的預後模型

梯度提升、隨機森林、深度網路與生成式序列模型,能產生比線性模型銳利得多的孿生,捕捉非線性、高維的基線結構來預測每位病人的未治療軌跡。

② 交叉擬合與校準

用交叉擬合/樣本分割,讓每位病人的孿生來自沒在他身上訓練過的模型,並重新校準(isotonic/Platt)讓 Ŷ₀ 準確。雙重穩健估計式(AIPW、TMLE)把孿生與治療模型配對,在觀察性情境提供額外保護。

以人機協作建立預後模型(HACHI)

孿生的好壞完全取決於它的預後模型。HACHI(Feng 等 2026,npj Digital Medicine)以「人在迴圈、AI 代理人」的流程建立這類模型,並讓它完全可解讀,臨床醫師能審視哪些概念(包含從病歷文字挖出的)進入模型,提升孿生所仰賴的校準與信任。

③ 過擬合與資料漂移

彈性孿生可能擬合到雜訊(過度樂觀的預測),或在部署族群與訓練不同時悄悄退化(資料漂移)。以留存校準、事先指定孿生、與漂移監測來防範,孿生若是錯的,精準度毫無價值。

如果……?對數位孿生做壓力測試

數位孿生把效果估成「實際值減去模型預測的對照」。它可不可信,取決於那個預測是否校準、是否仍適用於今天的病人、以及它是被當成單純的精準度調整、還是對照臂的完全替身。三個「如果」把差別講清楚。

① 如果孿生校準不良?

若 Ŷ₀ 系統性偏高或偏低,「實際 − 孿生」的對比就剛好被那個誤差弄偏,連 PROCOVA 的精準度收益也會縮水。務必在留存對照上檢查校準,依賴孿生前先重新校準。

② 如果族群自訓練後已改變?

在較早年代或不同場域訓練的孿生,可能不再描述你的病人未治療病程(新標準照護、不同病例組成)。此時孿生不可轉移,當它取代同期對照時最危險,正是歷史對照陷阱。

③ 如果是調整 vs 當對照臂?

在隨機試驗中當共變項(PROCOVA)時,隨機化保證無偏,孿生只是增加精準度,是低風險的收益。當合成對照取代隨機化時,預後模型承擔全部辨識重擔,是強得多、且無法檢驗的假設。

缺失資料與多重插補

真實世界的資料常有缺失值:某個檢驗沒開、某個共變項沒記。你怎麼處理這些缺失值,會改變你的因果估計。妥當的做法通常不是把不完整的列直接刪掉。這一頁講三種缺失機制、常見的處理策略,並用一個即時示範看:刪列或用平均值填,會錯;而多重插補能把真值救回來。

三種缺失機制(Rubin)

MCAR missing completely at random

完全隨機缺失:缺失和任何事都無關,試管隨機破了。刪掉不完整的列不會偏(只是浪費資料);但平均值插補仍會扭曲關聯。

MAR missing at random

隨機缺失:是否缺失取決於你有觀察到的東西(如病重、結果較高的人較常被檢驗)。這時刪列分析會偏;用上觀察到的變數做多重插補(或反機率加權)才有效。

MNAR missing not at random

非隨機缺失:是否缺失取決於那個沒被觀察到的值本身(最重的人根本沒來)。光靠資料沒有方法能修,需要敏感度分析與假設。

處理策略:從最差到最好

① 完整個案(整列刪除),只要有缺失值就把整列丟掉。簡單,但浪費資料、而且在 MAR 下會偏。② 單一插補(平均/中位數/單次迴歸),每個缺失值只填一個數。它低估了不確定性(信賴區間太窄),而用平均值填會把變數壓平、留下殘留混淆。③ 多重插補(MI/MICE),用一個含其他變數、也含結果的模型把每個缺失值填很多次,分別分析每份補完的資料,再用 Rubin 規則合併。在 MAR 下有效,且把不確定性也算進去。④ 模型法(FIML、對缺失做 IPW),其他同樣嚴謹使用觀察資料的做法。

當你無法假設 MAR:M-value

M-value:缺失資料偏誤的單一數字敏感度分析(Mathur 2023)

多重插補只有在資料是 MAR 時才有效,而 MAR 無法檢驗,因為你永遠看不到缺掉的值。M-value 是 E-value 的「缺失資料版」:它報出「缺掉的值要比 MAR 模型預測的偏離多少(也就是往 MNAR 的偏離要多強)」才能推翻你的結論。M-value 大,代表結果對合理的 MNAR 很穩;小,代表結果是靠 MAR 假設撐著。

用三種缺失機制來讀它,附例子:

  • MCAR:試管隨機破掉。缺失可忽略,用不到 M-value。
  • MAR:病重(已記錄的嚴重度較高)的人較常被檢驗,缺失只取決於已觀察的變數。此時 MI 有效,但前提是你假設 MAR 成立。
  • MNAR:最重的病人根本沒來,是否缺失取決於沒被觀察到的值本身。此時 MI 會偏;M-value 就問:這種 MNAR 機制要多強,才會改變答案?

為什麼重要:就像未測混淆的 E-value,M-value 讓你能嚴謹地繼續使用觀察資料,同時把一個無法驗證的假設(MAR)講清楚。把它和插補後的估計一起報,讀者就能判斷 MAR 假設到底承擔了多少,而不是把單一插補數字當成「缺失已解決」。(Mathur 2023。)

② 互動:在缺失下看各策略

即時示範:一個有缺失值的混淆 X

治療 A 與結果 Y 被 X 混淆(必須校正 X)。用上完整 X 的正確校正效果是 1.5;不校正的未校正估計約 2.3。現在把一部分 X 挖掉,看每個策略怎麼變。拖動滑桿、切換機制。

長條:每個策略估出的校正 A→Y 效果,對比真值 1.5(綠虛線)與被混淆的未校正值。平均值插補偏向未校正;完整個案在 MCAR 下還好、MAR 下會偏;多重插補貼著真值。合成教學資料。

③ 資料分析:實際跑多重插補


程式(SAS · R · Stata):多重插補

出處 — R 使用 mice 套件,mice() → with() → pool() 的呼叫方式同 mice 官方 vignette 與 van Buuren & Groothuis-Oudshoorn (2011, JSS) 套件論文;SAS 段為 proc mi / proc mianalyze 官方文件的標準流程。

這是可直接在可下載的 miss_sample.csv 上完整執行的程式(欄位:pid, A, x1, x2, x3, Y;Y 與 x2 含缺失值)。

SAS — proc mi / mianalyze

/* import the sample */
proc import datafile="miss_sample.csv" out=d dbms=csv replace;
    getnames=yes;
run;
/* create 20 imputations */
proc mi data=d nimpute=20 out=imp seed=123;
    var A x1 x2 x3 Y;
run;
/* analyse each imputed data set */
proc reg data=imp outest=est covout;
    by _Imputation_;
    model Y = A x1 x2 x3;
run;
/* combine results by Rubin's rules */
proc mianalyze data=est;
    modeleffects Intercept A x1 x2 x3;
run;

proc mi 插補、proc reg 分析每組、proc mianalyze 依 Rubin 規則合併。

R — mice

# load data and package
library(mice)
d <- read.csv("miss_sample.csv")
# 20 imputations by chained equations
imp <- mice(d, m = 20, seed = 123, printFlag = FALSE)
# fit the analysis model on each imputed data set
fit <- with(imp, lm(Y ~ A + x1 + x2 + x3))
# pool with Rubin's rules
summary(pool(fit))

mice() 建立 20 組插補;with() 逐組配適、pool() 合併估計。

Stata — mi impute chained

* import the sample
import delimited "miss_sample.csv", clear case(preserve)
* declare and impute Y and x2 by chained equations
mi set wide
mi register imputed Y x2
mi impute chained (regress) Y x2 = A x1 x3, add(20) rseed(123)
* pooled analysis
mi estimate: regress Y A x1 x2 x3

mi impute chained 插補 Y 與 x2;mi estimate 依 Rubin 規則合併迴歸。

④ 假設檢驗:你能站得住哪種缺失機制?

每一種插補方法,都只在某個關於「資料為什麼缺失」的假設下才有效。殘酷的事實:最關鍵的分野,MAR vs MNAR,無法用觀察到的資料檢驗。你只能用設計知識去論證,並盡量檢查能檢查的。

MCAR:部分可檢驗

MCAR 可以檢查:拿「有值」與「缺值」的列,在你有記到的變數上比較(如 Little's MCAR 檢定,或 t 檢定/標準化差異)。若有差異,MCAR 被否定,但「沒被否定」不等於成立。

MAR:用假設、無法證明

MAR 說是否缺失只取決於觀察到的變數。它是「多重插補/IPW 有效」背後的主力假設,但無法檢驗。讓它更可信的方法:在插補模型裡放進大量能預測該值與其缺失的變數(尤其是結果)。

MNAR:需要敏感度分析

若缺失取決於沒被看到的值,任何把資料補完的做法本身都不對。唯一妥當的回應是假設一個偏離 MAR 的程度、看答案會移動多少(⑥ 分頁),而不是相信單一個補出來的數字。

這在因果分析裡的位置

缺失資料是疊在混淆之上的第二個辨識問題:再完美的設計(本工具箱任一方法)也可能因為缺失處理不當而前功盡棄。在 MAR 下,多重插補或「對缺失做反機率加權」可恢復有效性;在 MNAR 下,要附敏感度分析。插補模型至少要和你的分析模型一樣豐富,而且必須包含結果與治療。

⑤ 用 AI/ML 強化:更有彈性的插補

插補模型本質上就是個預測問題,所以機器學習能自然套進來,當關係是非線性、或變數多且互相牽連時特別有用。它換的是引擎、不是假設:ML 插補一樣只在 MAR 下才有效。

樹模型:missForest/RF-MICE

用隨機森林當每個變數的插補器(R 的 missForest,或 mice 設 method='rf';Python 的 IterativeImputer(estimator=ExtraTrees…))。幾乎不用調參就能抓非線性與交互,混合型資料的好預設。

鄰居法與深度模型

KNN 插補用相似的完整列來填(簡單、單次)。去雜訊自編碼器/GAIN 學整體聯合分布,在大型高維資料上可能出色,但需要大量資料與細心,在表格式臨床資料上很少贏過 MICE。

陷阱:仍要做「真正的」多重插補

單次 ML 填值和平均值插補一樣低估不確定性。要得到有效推論,仍需多次抽樣(如對 ML 預測做 predictive-mean matching,或多份後驗樣本)再用 Rubin 規則合併。ML 也救不了 MNAR、或漏掉結果的模型。

⑥ 如果……?對 MNAR 做壓力測試

因為 MAR 無法檢驗,真正的問題是反事實的:如果缺失其實是有訊息的(MNAR)呢?你無法證明它不是,所以改去量化「它要嚴重到什麼程度,才會改變你的結論」。

Delta/臨界點分析

把補出來的值平移一個 δ(例如假設缺失者系統性地更差)再重跑。臨界點就是讓結論翻盤的那個 δ,若需要大到不合理的 δ,代表你的結論對 MNAR 穩健。

型態混合與選擇模型

型態混合模型依缺失型態分別配適結果再合併,假設明白寫出;選擇模型把缺失機制一起建模。兩者都把那個無法檢驗的假設攤開、可調,而不是藏起來。

報範圍,不是單一數字

在可能 MNAR 下,要交出的不是一個點估計,而是「在各種合理偏離 MAR 下的結論範圍」,加上每個結論所依賴的假設。能在合理 MNAR 情境下存活的結果,可信度高得多。

系統性回顧與統合分析

本工具箱其他每個分頁都在產生一篇研究的估計。系統性回顧站在更上一層:用事先寫好、可重現的方法找出所有相關研究、評讀它們,並在適當時把它們統計地合併成統合分析。這一頁走過 Cochrane 的工作流程、示範一個即時的統合分析(固定 vs 隨機效果、異質性、漏斗圖)、說明 GRADE 怎麼評估這個合併答案的「證據確定性」,並如實交代 AI 工具(Rayyan、機器學習篩選、大型語言模型)到底幫得上什麼。

這在整個工具箱裡的位置

那 23 個方法回答「這一份資料說了什麼?」系統性回顧回答「整個證據體說了什麼?」,而每篇納入研究的品質(它是不是一個好的 IV/RDD/世代研究?)直接餵進回顧的「偏誤風險」步驟。統合分析的可信度,不會超過它納入的研究:把有偏的研究合併起來,只會得到一個很精確的錯答案(垃圾進、垃圾出)。

工作流程(Cochrane Handbook)

系統性回顧的定義,就是它的方法事先固定且有紀錄,任何人都能重做一次。經典步驟:

① 問題與計畫書(PICO)

把問題寫精準,族群 Population、介入 Intervention、對照 Comparator、結果 Outcome,然後在開始之前寫好並登錄計畫書(如 PROSPERO),讓方法不會被結果牽著走。

② 搜尋

在多個資料庫(PubMed/MEDLINE、Embase、CENTRAL……)外加灰色文獻與試驗登錄,建立全面、有紀錄的檢索式。目標是高召回率(不漏任何一篇),代價是精準度低(要篩很多)。

③ 篩選(雙人)

兩位審閱者各自獨立依納入條件篩標題/摘要、再篩全文;第三人仲裁分歧。全程記在 PRISMA 流程圖(找到 → 篩選 → 納入)。

④ 資料萃取

把效果估計、樣本數、研究特徵抽進結構化的表單(最好先試做並重複萃取)。這些就是你統合分析的每一列。

⑤ 偏誤風險

用領域式工具評讀每篇:隨機試驗用 RoB 2、非隨機研究用 ROBINS-I(混淆、選樣、分類、缺失、測量、報告)。你對 IV/RDD/世代設計的理解,在這一步派上用場。

⑥ 合併與 GRADE

做合併,可以是敘述式,或在研究夠相似時做統合分析。再用 GRADE 評估整體證據的確定性,並依 PRISMA 2020 報告。

逐章看 Cochrane Handbook

Cochrane Handbook for Systematic Reviews of Interventions(v6.5,2024)是這個領域的標準教科書。其中第 2 部:核心方法是每篇回顧都遵循的骨幹;第 1、3、4 部補上規劃、特殊主題與非隨機證據。以下是原創的逐章對照(標出處,不照抄原文):

章在講什麼(白話)
第 2 部 · 核心方法(骨幹)
1開始一篇回顧,團隊、範圍、在碰資料前先寫好計畫書並登錄(PROSPERO)。
2決定範圍與問題,寫出精準的 PICO(族群、介入、對照、結果)。
3納入條件與分組,資格規則,以及介入/結果如何分組以利合併。
4搜尋與選文,跨資料庫的全面檢索+雙人篩選(PRISMA 流程)。
5蒐集資料,結構化、先試做、重複的萃取(估計值與研究特徵)。
6效果量,RR、OR、RD、HR(二元/存活),平均差與 SMD(連續)。
7偏誤與利益衝突,威脅每篇研究效度的概念框架。
8隨機試驗的偏誤風險,RoB 2 工具(5 個領域;見下)。
9合併前準備,檢查可比性、處理單位與缺失的摘要資料。
10統合分析,逆變異數加權合併、固定 vs 隨機效果、異質性(下方示範)。
11網路統合分析,用直接+間接證據一次比較 3 個以上的治療。
12用其他方法合併,不適合做統合分析時(SWiM、計票……)。
13結果缺失造成的偏誤,報告/發表偏誤、漏斗圖、Egger(下方漏斗圖)。
14「結果摘要」表與 GRADE,評估整體證據的確定性(見下)。
15解讀結果與結論,從一個合併數字到它對決策的意義。
第 1、3、4 部 · 規劃、特殊主題與非隨機證據
I–V關於 Cochrane 回顧,介紹、規劃、報告、更新、回顧之回顧(overview)。
16–21特殊視角,公平性與特定族群、介入複雜度、病人自陳結果、不良反應、經濟證據、質性證據。
22–26其他主題,前瞻/活證據、RCT 的變形、非隨機研究的效果、非隨機研究的偏誤風險(ROBINS-I)、個別病患資料(IPD)。

Cochrane 的手冊與標準家族

其他回顧類型

除了介入,Cochrane 還出版診斷試驗準確度(敏感度/特異度的統合分析)、預後與預測模型(PROBAST)、以及 Cochrane–Campbell 的質性證據合併手冊。各有自己的偏誤工具與合併方法。

MECIR 標準

Cochrane 介入回顧的方法學期望,一篇 Cochrane 回顧必須達到的、明確可稽核的執行與報告標準(必要 vs 高度建議項目),讓回顧一致而嚴謹。

風格與工具

Cochrane 風格手冊/Style Essentials 統一寫作與白話摘要;RevMan 是撰寫/統合分析軟體;GRADE(有自己的手冊)評估證據確定性。報告依 PRISMA 2020。

③ 資料分析:效果量與偏誤風險

效果量與偏誤風險(手冊第 6–8、25 章)

選對效果量(第 6 章)

二元:風險比 RR、勝算比 OR、風險差 RD。存活:風險比 HR。連續:同尺度用平均差 MD、不同尺度用標準化平均差 SMD。比值型(RR/OR/HR)在 log 尺度上合併。注意 OR/HR 的不可塌縮性(見「怎麼選」分頁)。

RoB 2:隨機試驗(第 8 章)

五個領域,各評低/有疑慮/高,再給整體判斷:① 隨機分派過程、② 偏離預定介入、③ 結果資料缺失、④ 結果的測量、⑤ 結果的選擇性報告。是逐結果、不是逐研究。

ROBINS-I:非隨機研究(第 25 章)

七個領域,以一個假想的目標試驗為基準:① 混淆、② 參與者選擇、③ 介入分類、④ 偏離預定介入、⑤ 資料缺失、⑥ 結果測量、⑦ 選擇性報告。這正是你的 IV/RDD/世代知識派上用場的地方。


程式(SAS · R · Stata):隨機效果統合分析

出處 — R 使用 metafor 套件,rma(method="REML") 與 forest() 的呼叫方式同 metafor 官方手冊與 Viechtbauer (2010, JSS) 套件論文示範。

這是可直接在可下載的 srma_sample.csv 上完整執行的程式(欄位:study, yi, sei)。

SAS — 以 PROC MIXED 做隨機效果

/* No native RE meta in SAS; PROC MIXED with known within-study variance approximates REML */
proc import datafile="srma_sample.csv" out=d dbms=csv replace;
    getnames=yes;
run;
data d; set d; v = sei*sei; run;
proc mixed data=d method=reml;
    class study;
    model yi = / solution;
    random int / subject=study;
    repeated / group=study;
    parms / parmsdata=d eqcons=1;
run;

PROC MIXED 以隨機 study 截距估計合併效果,固定截距的解就是 REML 合併估計值。

R — metafor::rma 與森林圖

# Random-effects (REML) meta-analysis and forest plot
library(metafor)
d <- read.csv("srma_sample.csv")
fit <- rma(yi = yi, sei = sei, data = d, method = "REML")
print(fit)
forest(fit, slab = d$study)

rma() 以 REML 配適隨機效果模型;print() 報告合併估計值、tau^2 與 I^2;forest() 繪製森林圖。

Stata — meta 指令

* Declare meta data with effect size and its standard error
import delimited "srma_sample.csv", clear case(preserve)
meta set yi sei, studylabel(study)
meta summarize, random(reml)
meta forestplot

meta set 宣告 yi 與其標準誤;meta summarize, random(reml) 以 REML 合併;meta forestplot 繪製森林圖。

② 互動:固定 vs 隨機效果

即時統合分析:固定 vs 隨機效果

12 場合成的疫苗試驗,每場是一個帶自己精度的 log 風險比。森林圖顯示每場試驗(方塊=估計、方塊大小=權重、鬚=95% CI)與兩個合併菱形。固定效果假設每場估的是相同效果、只用精度加權,當試驗其實有差異時,區間會窄而過度自信。隨機效果(DerSimonian–Laird)把研究間變異 τ² 加進去,把區間放寬以反映這點。拖動滑桿改變試驗之間真正的差異程度。

森林圖

漏斗圖(小研究效應)

固定效果合併 RR(95% CI)

–

隨機效果合併 RR(95% CI)

–

異質性 I²

–

當你把 τ 拉高,I² 上升、隨機效果區間變寬,而固定效果區間幾乎不動,這就是高異質性為什麼需要隨機效果模型(並去找原因),而不是一個假性過窄的固定效果 CI。合成教學資料。

④ 假設檢驗:異質性、漏斗與何時不該合併

解讀異質性與小研究效應

I² & τ²

τ² 是各研究真實效果的估計變異;I² 是總變異中「真正異質」而非抽樣誤差的百分比。粗略分級:0–40% 可能不重要、30–60% 中度、50–90% 實質、75–100% 相當大。I² 高 ⇒ 去探究(次群、統合迴歸),不要只是合併。

漏斗圖與發表偏誤

把每篇的效果對其精度作圖。對稱的倒漏斗=沒問題;某個底角有缺口暗示小型陰性研究沒被發表(發表偏誤)或小研究本就不同。Egger 檢定把不對稱量化,但研究少時檢定力低,要謹慎解讀。

固定還是隨機?

用問題來選、不是用 p 值:固定效果瞄準「唯一的共同效果」(在多樣的試驗間很少成立);隨機效果瞄準「一群效果分布的平均」。多數臨床統合分析預設用隨機效果,並報一個預測區間,指出未來一篇新研究的效果可能落在哪。

不只一個合併數字(手冊第 11–13 章)

不適合做統合分析時(第 12 章)

如果研究太異質、合不出一個數字,就別硬合。結構化的替代:SWiM(不做統合分析的合併,透明報告)、依效果方向計票、合併 p 值、或摘要效果的範圍與分布。一個誤導的合併估計,比謹慎的敘述式合併更糟。

網路統合分析(第 11 章)

一次比較三個以上治療,結合直接證據(正面對決試驗)與間接證據(透過共同對照)。它能對治療排名,但建立在可傳遞性(網路彼此可比)與一致性(直接與間接相符)上;信任排名前先檢查這兩者。

結果缺失造成的偏誤(第 13 章)

整篇研究(或某結果)因結果不討喜而未發表,會把合併往上偏。防線:含試驗登錄與灰色文獻的全面檢索、漏斗圖與 Egger 檢定(下方)、以及選擇模型/trim-and-fill 敏感度分析。預防勝於校正,登錄計畫書。

⑥ 如果……?這個合併答案有多確定(GRADE)

GRADE:這個合併答案有多確定?

合併估計不是終點,GRADE 為每個結果評估證據的確定性(高/中/低/極低)。整體證據對隨機試驗起始為高、觀察性研究起始為低,然後上下調整:

  • 降級因素:偏誤風險、不一致(高異質/無法解釋的 I²)、間接性(研究和你的 PICO 不太對得上)、不精確(合併 CI 太寬/事件太少)、發表偏誤(漏斗不對稱)。
  • 升級(主要用於觀察性證據)因素:效果很大、有劑量反應梯度、或所有合理的混淆都只會削弱觀察到的效果。

產出是「結果摘要表」:合併效果加上一個透明的證據確定性評等,讓決策者能據以行動。

⑤ 用 AI 強化:自動化與篩選

AI 與自動化:真正幫得上什麼(與其限制)

篩選數千筆標題是最耗人力的一步,所以自動化在這裡最成熟。對證據的解讀:

Rayyan 與主動學習

Rayyan(逾百萬審閱者、逾三百萬篇回顧)讓兩位審閱者平行、互盲地篩選,自動去重大型參考集,並用「預測相關性」(五星/zero-shot 評分)把未篩的堆排序:你標一些、模型重新排序,相關的記錄就提早浮上來。它加速人工篩選,但不取代雙人審閱的判斷,衝突仍要你裁定。

機器學習分類器

用你標好的決定訓練,ML 分類器在篩選階段可達高召回(某動物研究回顧約 98%),甚至能標出可能的人為錯誤,把「模型與人不一致」的記錄挑出來。你設定召回目標(盡量不漏該納入的),換取省下的工作量。

大型語言模型(LLM)

近期研究測試用 LLM(GPT 級)直接依納入條件篩摘要,敏感度看好但精準度浮動,提示詞與門檻很關鍵,仍需人最終裁定。動機很實在:連人類審閱者之間的一致性都不完美,這正是要兩位審閱+一位仲裁的原因。

實際做統合分析(R):doing-meta.guide/meta 與 metafor 套件

# library(meta): inverse-variance meta-analysis with both models + I^2 + forest/funnel
m <- metagen(TE = yi, seADTE = sei, studlab = trial,
             sm = "RR", common = TRUE, random = TRUE)   # common = fixed, random = DL
forest(m); funnel(m); metabias(m, method = "linreg")     # forest, funnel, Egger
# library(metafor): rma(yi, vi, method = "REML"); the doing-meta.guide book walks this end-to-end

Harrer 等人的免費指南《Doing Meta-Analysis in R》(doing-meta.guide)是很實用的搭配。它的路線圖對應上面的流程:效果量(第 3 章)→ 合併(第 4 章)→ 研究間異質性(第 5 章)→ 森林圖(第 6 章)→ 次群分析(第 7 章)→ 統合迴歸(第 8 章)→ 發表偏誤(第 9 章),再到進階主題:多層次(第 10 章)、SEM(第 11 章)、網路(第 12 章)與貝氏(第 13 章)統合分析,外加檢定力分析、偏誤風險圖與可重現報告。

結論

統合分析把許多研究變成一個帶信賴(與預測)區間的數字,但它的可信度完全取決於透明、事先登錄的方法、謹慎的偏誤風險評讀,以及一個不浮誇的 GRADE 評等。AI 加速篩選的苦工;它不提供判斷。合併的應是可比、執行良好的研究,當它們不可比時,就明說並去探究原因,而不是硬湊出一個數字。

網路統合分析(NMA)

一般的統合分析合併兩種治療的正面對決試驗。但臨床上要在很多種之間選擇,而且很少有試驗直接比過每一對。網路統合分析把所有治療連成一個網路,一次估出每一對的對比,做法是把直接證據(真的比過這兩者的試驗)與間接證據(透過共同對照推出來)結合。它甚至能對選項排名。代價是多了一個大假設,可傳遞性,以及一個直接 vs 間接的一致性檢查。

直接、間接與混合證據

如果有試驗比過 A vs 安慰劑 與 B vs 安慰劑,但沒人直接做 A vs B,你仍能間接估出 A vs B:(A−安慰劑)−(B−安慰劑)。安慰劑就是橋接兩者的共同對照。當「直接 A vs B 試驗」和「間接路徑」都存在時,NMA 把它們合併成更精確的混合估計,並檢查兩者是否相符。

② 互動:間接比較與一致性

即時示範:間接比較與一致性檢查

一個小網路:安慰劑、藥 A、藥 B。我們有 A-vs-安慰劑(log RR −0.40)與 B-vs-安慰劑(−0.25)的直接試驗。所以 A-vs-B 的間接效果=(−0.40)−(−0.25)=−0.15。現在想像有一場直接 A-vs-B 試驗,拖動它的結果。當直接估計和間接估計相符時,網路一致(迴圈閉合);當兩者背離,就是不一致(incoherence),硬把它們合成一個數字會誤導。

治療網路

直接 vs 間接 A-vs-B

間接 A-vs-B(經安慰劑)

–

直接 A-vs-B(滑桿)

–

不一致(直接 − 間接)

–

效果為 log 風險比(負=前一個藥較好)。當滑桿停在間接值(−0.15)時迴圈一致;移開就打開一個不一致,這正是 node-splitting/net-heat 圖會標出來的。合成教學資料。

④ 假設檢驗:可傳遞性與一致性

讓它成立的假設

可傳遞性(最關鍵)

間接路徑只有在組成它的試驗可比時才有效,效果修飾子(年齡、嚴重度、年代、劑量……)在 A-vs-安慰劑 與 B-vs-安慰劑 兩組間分布相似。若 A 的試驗收的病人重很多,安慰劑就不再是公平的橋。可傳遞性是臨床/流行病學的判斷,大多無法用資料檢驗。

一致性(可檢)

可傳遞性的統計影子:在同時有直接與間接證據的迴圈裡,兩者應該相符。用 node-splitting(把每個對比拆成直接、間接、網路三份)、net-heat 圖(netmeta)、或design-by-treatment 交互檢定來查。不相符=不一致,去探究,別只是合併。

網路幾何

先把網路畫出來:節點=治療、連線=直接比較(越粗=試驗越多)。連結良好、有閉合迴圈的網路撐得起 NMA;星形(全部只對安慰劑)只有間接估計、沒有一致性可查;孤立的節點根本排不了名。

⑥ 如果……?太相信排名會怎樣

網路統合分析可以把每個治療排成第 1、第 2、第 3……,而這個排名是這個領域最容易被過度解讀的輸出。要一直問的反事實是:如果這個排序其實是不精確或不一致造成的假象、而非真實差異呢?

對治療排名:與它的陷阱

NMA 能依「是最佳的機率」對每個治療排名。SUCRA(累積排名曲線下面積;頻率學派的孿生是 P-score)把它摘成 0–100%。Rankogram 顯示可能名次的整個分布。解讀排名要小心:

  • 一個治療可能靠微小又不精確的效果排第一,排名忽略了差異有多大、多確定。一定要把排名和實際效果估計與區間並排看。
  • 網路稀疏或不平衡時排名不穩;一場新試驗就可能把它洗牌。要報不確定性(rankogram),不是只報冠軍。

③ 資料分析:配適、評估與報告網路

怎麼做、怎麼評(Cochrane NMA 工具箱;doing-meta.guide)

頻率學派:netmeta(R)

圖論取向(借自電網理論)用加權最小平方擬合整個網路;給 league table(netleague)、net-heat 圖、相對參考治療的森林圖、P-score,以及全網路的 I²/τ²。

貝氏:gemtc/BUGSnet

用 MCMC 擬合的階層模型(gemtc/JAGS、BUGSnet);自然處理多臂試驗、給完整後驗、SUCRA 與 rankogram,但要檢查收斂(trace plot、Gelman–Rubin)。兩治療的間接捷徑是經典的 Bucher 法。

證據確定性:CINeMA + 報告

CINeMA 把 GRADE 改寫到網路上(研究內偏誤、報告偏誤、間接性、不精確、異質性、不一致),評每個 NMA 估計的證據確定性。依 PRISMA-NMA 延伸報告。Cochrane NMA 工具箱整理了相關軟體(netmeta、gemtc、BUGSnet、mvmeta、ITC)。

結論

NMA 很強,即使沒有正面對決試驗,也能回答「這些之中哪個最好?」,但它在一般成對統合分析已需要的一切之上,再疊一個大多無法檢驗的假設(可傳遞性)。先畫網路、用臨床理由論證可傳遞性、在有迴圈的地方檢驗一致性、把排名與效果量並排讀、用 CINeMA 評強度。一個來自不一致或不平衡網路、看起來很有信心的排名,比直接說「分不出來」更糟。


程式(SAS · R · Stata):網路統合分析

出處 — R 使用 netmeta 套件,pairwise() → netmeta() → netgraph() 的流程同 netmeta 官方手冊與 Balduzzi 等 (2023, R Journal) 套件論文示範。

這是可直接在可下載的 nma_sample.csv 上完整執行的程式(欄位:study, treatment, events, n)。

SAS — 無原生 NMA(說明)

/* SAS has no standard frequentist NMA; a Bayesian NMA can be coded in PROC MCMC. */
/* Here we just import and summarise events per treatment as a starting point. */
proc import datafile="nma_sample.csv" out=d dbms=csv replace;
    getnames=yes;
run;
proc means data=d sum;
    class treatment;
    var events n;
run;

頻率學派 NMA 的標準工具是 R 的 netmeta;在 SAS 中得用 PROC MCMC 自己建貝氏模型,所以這裡只先做資料彙總。

R — netmeta

# Arm-level data -> pairwise contrasts -> network meta-analysis
library(netmeta)
d <- read.csv("nma_sample.csv")
p <- pairwise(treat = treatment, event = events, n = n,
              studlab = study, data = d, sm = "OR")
net <- netmeta(p)
print(net)
netgraph(net)

pairwise() 將各組計數轉為對比;netmeta() 配適頻率學派網路模型(OR);netgraph() 繪製證據網路圖。

Stata — network/mvmeta(說明)

* Stata NMA uses White's network suite built on mvmeta (user-written). 
import delimited "nma_sample.csv", clear case(preserve)
* network setup events n, studyvar(study) trtvar(treatment) or
* network meta consistency
list study treatment events n in 1/8

在 Stata 中需安裝 network 與 mvmeta 套件,network setup 建立對比、network meta 配適模型;這兩行先註解起來,沒裝套件也能執行這段。

⑤ 用 AI/ML 強化:對 NMA 幫得上什麼(與幫不上的)

NMA 是用既有試驗的彙總結果建起來的,所以機器學習不會替你估出網路,但它在周邊幫得上忙,而且有些統計延伸能超越單純的網路。

建立證據庫

NMA 的工是餵給它的系統性回顧:ML 輔助篩選(Rayyan、主動學習)與用 LLM 從 PDF 抽取臂別、結果與效果量,能加速組裝網路,和系統性回顧頁同一套工具,仍需人最終裁定。這裡的錯誤會傳進每一個對比,所以抽取準確度更重要、不是更不重要。

成分 NMA 與統合迴歸

當治療是組合(藥 A、A+B、A+B+C)時,成分 NMA 對每個成分的貢獻建模,而不是把每個組合當成互不相關,這是一種結構化、迴歸式的「借力」。網路統合迴歸用研究層級的效果修飾子校正對比,這也是論證可傳遞性的正規做法。

ML 救不了什麼

沒有演算法能修好被破壞的可傳遞性、稀疏或不連通的網路、或不一致的迴圈,那些是證據的性質,不是估計器的。ML/貝氏的彈性甚至可能把這些問題藏在一個有信心的排名後面。先用診斷(node-splitting、CINeMA);只有在網路站得住腳後,才動用更花俏的模型。

結論

對 NMA 來說,機器學習是組裝與抽取證據的加速器,成分模型/統合迴歸則是有原則的統計延伸,但網路的可信度仍取決於可傳遞性、一致性、以及一個連通且報告良好的網路,這些都不是 ML 能無中生有的。

群組軌跡模型(GBTM)

很多暴露與結果不是單一數字,而是一個隨時間變化的形狀,逐月的服藥順從度、追蹤期間的生物標記、反覆的用藥劑量。把所有人平均成一條曲線,會把真正重要的差異蓋掉。群組軌跡模型(GBTM;Nagin)假設整個族群是少數幾個潛在群組的混合,每組各自走一條軌跡,並用最大概似法還原這些群組形狀、每個人屬於各組的機率、以及每組的大小。它是一個描述/分群工具,用來摘要縱貫資料裡的異質性,本身不是因果設計。

GBTM vs 成長曲線 vs 成長混合模型

一般的成長曲線(隨機效果/潛在曲線)給出一條族群軌跡,個體在它周圍散布。GBTM(又稱潛在類別成長分析 LCGA)則把族群切成 K 個不同群組,每組各有自己的多項式形狀,而且關鍵是假設組內沒有個體變異(組內變異固定為 0)。成長混合模型(GMM)介於兩者之間:有 K 組、同時每組曲線周圍還有隨機效果。GBTM 犧牲組內的真實性,換取簡單、好解讀、彼此區隔清楚的群組。

模型

每個群組 k 有一個成員機率 πₖ 與一條對時間/年齡的多項式軌跡(截距 → 線性 → 二次 → 三次)。在給定成員身分下,重複測量的結果服從一個選定的分布:有界連續分數用設限常態(censored normal, CNORM)、計數用零膨脹卜瓦松(zero-inflated Poisson, ZIP)、二元結果用邏輯斯(logit)。參數以最大概似(EM)估計。

輸出什麼

對每個人,給出屬於各組的後驗機率;通常再把人指派到最可能的那一組。另外給出每組軌跡的估計形狀與該組占族群的比例。你還能加入預測「屬於哪一組」的風險因子,以及讓軌跡平移的時變共變項。

用在哪

藥物流行病學與族群健康:順從度軌跡(逐月 PDC)、追蹤期間的血壓/糖化血色素/eGFR、鴉片類藥物(opioid)的用藥型態、醫療花費路徑、發展心理學(Nagin 最早的應用領域:兒童攻擊行為)。常作為第一步的描述,得到的群組再餵進後續分析。

② 互動:還原藏起來的軌跡群組

即時示範:還原藏起來的順從度軌跡

一個合成的病人世代追蹤 12 個月;每條線是一個人的順從度(0–1)。裡面藏著幾個真實的軌跡群組(持續高、逐漸下降、早期中止)。選擇你要 GBTM 配適幾組 K:它會跑一個多項式軌跡的 EM 混合模型,畫出每個估計的群組平均(粗線)、用所屬群組替每個人上色,並回報配適度。看看組數太少會把不同形狀混成一條、太多會把一個真實群組拆成兩個長得很像的群組,以及 BIC 怎麼指向正確的組數。

軌跡(個體+估計的群組平均)

模型配適:各組數的 BIC

BIC(越低越好)

–

平均後驗機率(AvePP,目標 ≥ 0.7)

–

各組大小(指派比例)

–

這裡的真相是 3 組。K 小於 3 時 BIC 偏高、不同形狀被迫共用一條曲線;K = 3 時 BIC 觸底、AvePP 高(分群乾淨);再把 K 加大,BIC 幾乎不再改善,卻開始把一個真實群組拆開,AvePP 下降並產生一個很小、不穩的群組。合成教學資料;指派依最大後驗機率。

③ 資料分析:配適模型與選擇組數

選幾組(別只信 BIC)

決定 K 是最核心的判斷。要同時看統計與實質:群組數較少、可解讀、臨床上有意義的分群,勝過一堆讓 BIC 最佳、卻零碎的群組。

BIC(與肘點)

配適 K = 1, 2, 3…比較 BIC;越低越好。它常會一直緩慢下降,所以要找肘點,也就是再多一組也換不到多少改善的位置,而不是直接取全域最小值,後者在大樣本容易抽出過多群組。

平均後驗機率(AvePP)

對每個群組,把被指派進去的成員「屬於它的後驗機率」平均起來。每組都 AvePP ≥ 0.7 代表分類乾淨(此指標在文獻中也寫作 APPA,average posterior probability of assignment)。AvePP 低=群組重疊、指派不確定,這時別把標籤當成確定的事實。

OCC、組大小與校準

每組正確分類勝算(odds of correct classification, OCC)> 5;每組要大到有實用價值(常見經驗法則是 ≥ 5%);而且估計的成員機率 πₖ 要和指派的比例相符。一個很小、OCC 低、或無法重現的群組,多半是統計假象。


程式(SAS · R · Stata):群組軌跡模型

出處 — R 使用 lcmm 套件,hlme(mixture=) + gridsearch() + summarytable() / postprob() 的選組流程同 lcmm 官方 vignette 與 Proust-Lima, Philipps & Liquet (2017, JSS) 套件論文;多變量版用 gbmt 套件(其官方手冊)。

這是可直接在可下載的 gbtm_sample.csv 上完整執行的程式(欄位:pid, time, y)。

SAS — PROC TRAJ 巨集

/* SAS uses Jones & Nagin's PROC TRAJ add-on; data must be one row per pid (wide). */
proc import datafile="gbtm_sample.csv" out=d dbms=csv replace;
    getnames=yes;
run;
proc transpose data=d out=wy prefix=y;  by pid; id time; var y;  run;
proc transpose data=d out=wt prefix=t;  by pid; id time; var time; run;
data wide; merge wy wt; by pid; run;
/* %traj fits 3 quadratic groups (order 2 2 2) once PROC TRAJ is installed */
proc traj data=wide out=of outplot=op;
    id pid; var y1-y5; indep t1-t5;
    model cnorm; min 0; max 100; ngroups 3; order 2 2 2;
run;

PROC TRAJ(Nagin/Jones)在轉成每位受試者一列後,配適三個二次軌跡群組。

R — lcmm::hlme+gridsearch(穩健起始值)、選組、後驗分類

# Group-based trajectory model with lcmm (Proust-Lima 2017)
library(lcmm)
d <- read.csv("gbtm_sample.csv")

# 1-class reference model: also supplies starting values for the mixtures
m1 <- hlme(y ~ poly(time, 2), subject = "pid", ng = 1, data = d)

# gridsearch = many random restarts -> avoids local optima (Edwards 2023)
m2 <- gridsearch(hlme(y ~ poly(time,2), mixture = ~poly(time,2),
                     subject="pid", ng=2, data=d), rep=30, maxiter=15, minit=m1)
m3 <- gridsearch(hlme(y ~ poly(time,2), mixture = ~poly(time,2),
                     subject="pid", ng=3, data=d), rep=30, maxiter=15, minit=m1)

# choose K: lowest BIC, every class >=5%, clean classification (APPA >=0.7)
summarytable(m1, m2, m3, which=c("G","loglik","npm","BIC","%class","entropy"))
postprob(m3)                                   # APPA + class sizes for K=3

# keep the most-likely class per subject, then plot the group trajectories
d$class <- m3$pprob$class[match(d$pid, m3$pprob$pid)]
plot(m3, which = "fit", var.time = "time")

# several outcomes jointly (multi-trajectory)? use gbmt (Nagin 2018; Magrini 2022):
# gbmt::gbmt(x.names=c("y1","y2"), unit="pid", time="time", ng=3, d=2, data=dwide)

單次 hlme 可能停在局部最佳,所以指引(Edwards 2023)用 gridsearch 做隨機重啟;summarytable 以 BIC 比較組數 K,postprob 給 APPA/各組大小(選 BIC 最低、每組 ≥ 5%、APPA ≥ 0.7),$pprob$class 即後驗歸類。要同時處理多個指標時,gbmt 套件可配適群組多變量軌跡模型。

Stata — traj 外掛

* Stata uses Jones & Nagin's user-written -traj- plugin (needs wide data)
import delimited "gbtm_sample.csv", clear case(preserve)
reshape wide y, i(pid) j(time)
* traj, var(y0-y4) indep(0 1 2 3 4) model(cnorm) min(0) max(100) order(2 2 2)
* trajplot, xtitle("time") ytitle("y")
list in 1/5

轉為寬資料後,traj 外掛配適三個二次群組,trajplot 繪圖;先註解起來,沒裝外掛也能執行這段。

④ 假設與陷阱

群組是方便的近似,不一定是真實的次型

GBTM 一定會給出群組,即使族群的變化其實是連續的。Nagin & Tremblay 自己的提醒,「群組是近似、不是字面上的實體」,很關鍵:這些離散群組是用來描述連續變化的統計工具,把它們當成真實存在的實體(「這就是四種病人」)可能誤導。把軌跡群組當成摘要、加以驗證(重現、外部關聯),並明白說明成員身分是不確定的。

下游的分類不確定性

如果你把指派的群組拿去當後續迴歸的暴露或結果,就忽略了後驗的不確定性,可能讓估計與標準誤偏掉。最好改用能把後驗機率一併帶入的方法(例如以後驗機率加權、或聯合/一步式(one-step)模型),至少要證明結論對它是穩健的。

設計上的敏感點

結果取決於測量時點、追蹤的長度與點數、選用的分布與多項式階數、以及樣本量。稀疏或時點不一致的資料、太短的序列,都會讓群組不穩。缺失資料與有訊息的脫落需要明確處理。

不是因果設計

GBTM 描述誰走什麼形狀;它本身不辨識治療的效果。它和本工具箱裡的因果設計天生互補,例如用來定義一個縱貫的暴露型態,再用目標試驗/g-method 去研究它。

⑤ 用 AI/ML 強化:把 GBTM 當非監督式學習

GBTM 本身就是一種機器學習模型,而 ML 還提供替代做法

GBTM 是一個受限的潛在類別/有限混合模型,用 EM 對縱貫曲線做的非監督式分群(互動示範跑的就是這個)。這樣看,機器學習既提供替代做法,也提供處理更大規模的能力:當形狀在時間上沒對齊時,用縱貫資料的 k-means(kml)或動態時間規整(DTW)做免模型分群;面對大量不規則序列時用深度/表徵學習分群;以及用梯度法配適(例如 Andrew Wheeler 的 PyTorch 實作)把 GBTM 擴展到大資料與自訂連結函數。ML 也能幫忙選 K(交叉驗證、資訊準則)與檢驗穩定度。提醒和往常一樣:更有彈性的分群一樣會從連續變化裡切出群組,務必驗證。

軟體與怎麼跑

SAS:PROC TRAJ

最早的實作(Jones & Nagin)。指定分布(CNORM/ZIP/LOGIT/BETA)、每組的多項式階數、可自行加入預測群組歸屬的風險因子,以及時變共變項(TCOV)。診斷指標(AvePP、OCC、組大小)內建就有。

Stata 與 R

Stata:traj 外掛(Jones & Nagin)對應 PROC TRAJ。R:lcmm(hlme 做 LCGA/GBTM、lcmm 做 GMM)、gbmt 做多變量群組軌跡、以及 crimCV。Mplus 與 Latent Gold 也能配適 GBTM/GMM。

Python

沒有單一公認套件,但這個模型其實就是迴歸的 EM 混合:Andrew Wheeler 的範例用 PyTorch 配適群組軌跡模型(同樣的想法用「迴歸的高斯混合」也只要幾行)。適合大資料與自訂連結函數。

R 範例(lcmm::hlme):配適 K 組,再看診斷

# library(lcmm): latent-class linear mixed model; ng = number of groups, here a quadratic in month
m3 <- hlme(adherence ~ month + I(month^2), subject = "id",
           ng = 3, mixture = ~ month + I(month^2), data = long)
summary(m3)                 # class proportions, BIC
postprob(m3)                # AvePP & posterior classification table per group
# refit ng = 1..6, compare BIC, then check AvePP >= 0.7, OCC > 5, group size >= 5%

上面的互動示範就是把同一套邏輯(多項式軌跡的 EM 混合,加上 BIC 與平均後驗機率)直接在你的瀏覽器、用合成資料跑出來。

⑥ 如果……?這些群組是真的嗎

GBTM 一定會給你乾淨的群組,所以真正該問的是一個反事實問題:如果其實根本沒有真實的群組呢?對答案做壓力測試,才能把「真發現」和「假象」分開。

如果真相是連續的?

一個真正連續的過程(每個人都在緩慢漂移)仍會被切成離散群組。檢查:群組在保留樣本裡會重現嗎?用沒參與配適的外部變數能區分它們嗎?連續模型是否配適得差不多好?若在任何一項下群組消失,就把它們當描述摘要、而非真實次型。

如果把標籤帶到下游?

把每個人指派到單一群組、再用這個確定的標籤當暴露/結果,會忽略分類的不確定性,可能讓後續估計與標準誤偏掉,AvePP 低時最嚴重。替代做法:以後驗機率加權、改用一步式/聯合模型,至少在多組合理的指派下重跑下游分析、證明結論穩健。

如果設計改變?

換不同的測量時點、更長或更短的追蹤、不同的分布(CNORM vs ZIP)或多項式階數,還會出現同樣的群組嗎?在這些設定下重配適,看哪些結論存活。對合理選擇的穩定性,才是「軌跡群組不只是建模假象」的真正證據。

結論

GBTM 把一團個體縱貫曲線變成少數幾個可解讀的軌跡群組,並附上每個人屬於各組的機率。它很適合描述隨時間的異質性,但它一定會給出群組,所以要用 BIC 加上判斷來選 K、檢查 AvePP/OCC/組大小、絕不把群組當成真實存在的實體、並把分類的不確定性帶進任何下游分析。用它來看見型態;用因果設計來解釋型態。

因果機器學習

本工具箱每個方法估的都是一個平均處置效果(ATE)。但同一個治療可能對某些人有益、對另一些人有害。因果機器學習更進一步:估條件平均處置效果(CATE),看你是誰(年齡、嚴重度、生物標記)而定的效果,做法是把彈性 ML 放進可動的零件。關鍵是它不會讓假設變鬆:識別仍需無未測混淆、重疊與一致性,正是本工具箱各設計所提供的。ML 減少的是建模偏誤;它無法把「預測得準」變出一個因果效果。

從 ATE 到 CATE:以及為何它不只是預測

預測模型學的是 E[Y | X],預期會出現什麼結果。因果模型學的是 E[Y¹ − Y⁰ | X],若你介入,對每個輪廓 X 結果會改變多少。兩者可能方向相反:一個預測壞結果的標記,可能正落在治療最有幫助的次群上。CATE 是個體化治療規則與政策學習的基礎,但錯的因果模型比錯的預測模型更危險,因為有人會照它行動。

② 互動:單一 ATE 藏住「誰受益」

即時示範:單一 ATE 藏住「誰受益」;meta-learner 把它找回來

240 位合成病人;真實效果隨共變項 X 變化(拖動異質性)。琥珀虛線是單一 ATE,所有人一個數字。青線是在你瀏覽器裡即時跑的真 T-learner:對治療組與對照組各配一條彈性曲線、再相減,它的差就追著真實 CATE(綠)。異質性為零時 ATE 就夠;調高後,ATE 嚴重誤判兩端的人。

單一 ATE(一個數字)
–
CATE 範圍(最低→最高 X)
–
實際被傷害的比例
–

這個 T-learner 是真的(兩條最小平方曲線相減),不是替身。異質性高時,只報 ATE 會對被傷害的病人說治療「平均有效」。合成教學資料。

③ 資料分析:估計 CATE

Meta-learner 工具箱

S-/T-learner

S-learner:一個模型把治療當特徵,分別預測 A=1、A=0 再相減。T-learner(本頁示範):兩個分開的模型,每臂一個。簡單、與模型無關(model-agnostic),但在某一臂資料較少時估計會比較不穩定。

X-/DR-learner

X-learner(Künzel 2019)為每個個體補上缺失的反事實再交叉擬合,臂不平衡時很強。DR-learner 用雙重穩健的擬結果,只要兩個輔助模型其一對,CATE 就有效。兩者都比 T-learner 更有效率。

因果森林與 R-learner

因果森林(Wager & Athey 2018;grf)讓樹依效果異質性分裂,給出帶誠實信賴區間的 CATE。R-learner(Nie & Wager 2021)與雙重/去偏 ML(Chernozhukov 2018)用交叉擬合把輔助部分正交掉,正是本工具箱 ⑤ 已用的 DML 想法。


程式(SAS · R · Stata):異質性處置效果

出處 — R 使用 grf 套件的 causal_forest()/average_treatment_effect(),呼叫方式同 grf 官方 vignette(CRAN: package=grf)。

這是可直接在可下載的 causalml_sample.csv 上完整執行的程式(欄位:pid, A, Y, x1, x2, x3, x4, x5)。

SAS — AIPW 輔助模型

/* import the sample */
proc import datafile="causalml_sample.csv" out=d dbms=csv replace;
    getnames=yes;
run;
/* propensity-score model */
proc logistic data=d noprint;
    model A(event='1') = x1 x2 x3 x4 x5;
    output out=ps p=g1;
run;
/* outcome model */
proc reg data=ps noprint;
    model Y = A x1 x2 x3 x4 x5;
    output out=q p=qhat;
run;
/* AIPW influence-function mean = average treatment effect */
data aipw; set q;
    if=(A/g1 - (1-A)/(1-g1))*(Y-qhat);
run;
proc means data=aipw mean; var if; run;

羅吉斯傾向分數與迴歸結果模型組成 AIPW 平均效果估計量。

R — grf causal_forest

# load data and package
library(grf)
d <- read.csv("causalml_sample.csv")
X <- as.matrix(d[, paste0("x", 1:5)])
# fit a causal forest for heterogeneous effects
cf <- causal_forest(X = X, Y = d$Y, W = d$A)
# overall average treatment effect
print(average_treatment_effect(cf))
# individual (CATE) predictions
head(predict(cf)$predictions)

causal_forest() 學習條件平均效果;average_treatment_effect() 給出整體 ATE。

Stata — teffects aipw

* import the sample
import delimited "causalml_sample.csv", clear case(preserve)
* augmented inverse-probability-weighted ATE
teffects aipw (Y x1 x2 x3 x4 x5) (A x1 x2 x3 x4 x5)

teffects aipw 以雙重穩健方式估計平均處置效果。

④ 假設檢驗:ML 改變了什麼、沒改變什麼

同樣的識別假設

無未測混淆、重疊/正性、一致性仍是必要的,它們來自設計、不是演算法。把因果 ML 用在有偏的設計上,只會給你一個精確、有異質性的錯答案。

誠實切分與交叉擬合

要對「資料自適應找到的 CATE」給出有效區間,要用樣本切分/誠實(一部分長模型、另一部分估效果)與交叉擬合。省略這步,彈性 ML 就會過度配適不存在的異質性。

真實世界資料的提醒

在 EHR/登錄上,Feuerriegel 等(Nature Medicine 2024)提醒:豐富特徵會誘你把好預測當因果效果、次群可能沒有重疊、選樣與缺失在個體層級的影響更嚴重。能對試驗基準驗證就驗證。

⑤ 用 AI/ML 強化:軟體與如何擴展

因果機器學習本身就是那層 AI,上面的 meta-learners 與森林就是「強化」。這裡是把它們跑起來、擴展到實務規模的工具,以及它和本工具箱其他部分的銜接。

動手做:軟體

Python,EconML(Microsoft;meta-learners、DML、因果森林、政策學習)、causalml(Uber)、DoubleML。R,grf(廣義隨機森林/因果森林)、DoubleML、rlearner。本工具箱多個方法的 ⑤「用 AI 強化」分頁,已經在跑這些想法的真實 DML/彈性輔助實例。

人機協作共同設計(HACHI)

當模型必須保持可解讀、可信任時,HACHI(Feng 等 2026,npj Digital Medicine)讓 AI 代理人與臨床專家在迴圈中協作:代理人用統計工具提出候選概念(甚至從自由文字病歷挖出),專家給回饋,最後得到一個完全可解讀的臨床預測模型。它是「在依個體層級估計行動前先建立信任」的治理/可解讀性層,而不是跳過可信因果設計的捷徑。

結論

因果機器學習是疊在本工具箱之上的自然下一層:先用一個可信的設計做識別,再讓彈性 ML 估誰受益、受益多少,配上誠實切分、交叉擬合與重疊檢查。當效果真的有異質、且你有足夠資料與重疊時,它才划算。它不是一條「不用設計、就能從髒資料得到因果答案」的捷徑。

⑥ 如果……?這個異質性是真的嗎

CATE 模型一定會畫出一幅「誰受益更多」的圖。要一直問的反事實是:如果其實沒有真正的異質性呢,或者整個效果只是 ML 估得很精準的殘留混淆呢?

如果根本沒有異質性?

彈性學習器會把雜訊變成假異質性。檢查:把 CATE 對共變項做最佳線性投影、畫校準/RATE 曲線、或單純看同樣的次群在保留樣本上會不會再出現。若「受益者」無法重現,就把平的 ATE 當成可靠答案。

如果還有殘留混淆?

ML 提升的是精度、不是識別,殘留混淆會變成一個有信心、有細節的錯 CATE。用和單一效果相同的敏感度工具對它做壓力測試(如對 ATE 算 E-value、陰性對照檢查)。在輕微未測混淆下就瓦解的發現,不是真的。

如果照它行動?

估 CATE 通常是為了一個政策(治療被預測會獲益的人)。在相信個體層級的精準分配前,先確實評估那個政策,在保留樣本上算政策價值/uplift,對照「全部治療」與「全部不治療」基準。平均預測準,不保證決策好。