資料庫研究與真實世界資料
健保資料庫不是為了研究而存在的,它是為了申報。這一章講那個落差造成什麼問題、台灣 NHIRD 特有的限制,以及一個七階梯的實跑示範——包括那個估對了答案卻用錯方法的階梯。
這些資料本來不是為了你而存在的
健保申報資料的目的是付錢。ICD 碼寫上去是為了說明這次診療為什麼該給付,不是為了記錄 「這個人確實得了這個病」。這個落差是資料庫研究所有方法學問題的源頭。
它的後果具體而且可預測:
| 申報邏輯 | 對研究的後果 |
|---|---|
| 診斷碼是為了給付而填 | 「疑似」與「確診」常常同碼;rule-out 診斷會留下紀錄 |
| 一次就診可填多個碼,順序不一定有意義 | 主診斷與次診斷的界線比想像模糊 |
| 沒申報的事不存在 | 自費項目、未就醫的疾病完全看不到 |
| 給付規則會改 | 同一個碼在不同年份代表的臨床情境可能不同 |
台灣 NHIRD 的特性
以下是做台灣健保資料研究時,設計階段就要納入考慮的幾件事。申請與使用規範會變動, 實際流程以主管機關當時的公告為準,這裡只講對研究設計的影響。
有什麼:門診與住院的診斷碼、處方(藥品、劑量、天數)、檢查與處置的申報項目、 手術碼、就醫日期與院所層級。涵蓋率接近全民,追蹤可以拉很長,而且不會因為搬家換醫院就追丟—— 這是它相對於單一醫院病歷最大的優勢。
沒有什麼(而且這些通常正是關鍵的干擾因子):
- 檢驗數值(申報看得到「做了 HbA1c」,看不到結果是多少)
- 影像與病理報告的內容
- 生活習慣:抽菸、飲酒、運動、BMI
- 疾病嚴重度:分期、功能分級、症狀
- 死因(需另外串連死亡登記檔)
- 未就醫的事件
疾病定義:編碼演算法要驗證
因為診斷碼不等於診斷,資料庫研究必須自己定義「什麼算是這個病」。常見的演算法形式:
- N 次門診或 1 次住院帶該診斷碼(最常見的形式)
- 診斷碼 + 相對應的處方(例如糖尿病碼加上降血糖藥)
- 診斷碼 + 特定檢查或處置
- 加上時間窗限制(例如一年內至少兩次)
這些演算法的準確度必須有依據。 理想是引用已發表的驗證研究(拿演算法對照病歷判讀, 報告 PPV / 敏感度);沒有的話,至少要做敏感度分析——換一個較嚴格與較寬鬆的定義各跑一次, 看結論穩不穩。
七個階梯:同一份資料,七種答案
這一節用模擬資料示範資料庫研究最常見的設計錯誤各自會造成什麼。 模擬設定:8000 人,真實的 HR 是 0.80(治療有保護效果), 對照藥沒有效果,暴露與預後之間有典型的依適應症干擾。 表中的「分析 n」是該列模型實際跑的那一份資料的人數,不是整個模擬世代的人數——設計一改,被納入分析的人就跟著換掉。
| 做法 | 分析 n(A/對照) | 事件數 | HR | 95% CI | 離真值 0.80 多遠 |
|---|---|---|---|---|---|
| 1. 天真比較(用藥 vs 沒用藥,不管時序) | 5092(2003/3089) | 1482 | 1.13 | 1.02–1.25 | 方向相反,且達顯著 |
| 2. 新使用者設計,但追蹤時間從研究窗開始算 | 5737(870/4867) | 1015 | 0.78 | 0.66–0.93 | ⚠️ 幾乎正中真值——但方法是錯的 |
| 3. 新使用者設計,時鐘釘在第一次處方,未校正 | 5737(870/4867) | 1015 | 1.34 | 1.13–1.59 | 方向相反 |
| 4. 新使用者 + 校正已測量的干擾因子 | 5737(870/4867) | 1015 | 1.01 | 0.85–1.20 | 回到接近 1,仍未偵測到保護效果 |
| 5. 新使用者 + 活性對照,未校正 | 1778(870/908) | 339 | 0.93 | 0.75–1.15 | 方向對了,未達顯著 |
| 6. 新使用者 + 活性對照 + 校正 | 1778(870/908) | 339 | 0.79 | 0.63–0.99 | 接近真值 |
| 7. 新使用者 + 活性對照 + IPTW | 1778(870/908) | 339 | 0.78 | 0.62–0.99 | 接近真值 |
figures/scripts/B6-06-target-trial.R從第 3 列到第 6 列可以看出兩個修正各自的貢獻:換成活性對照(第 3→5 列)處理了 「用藥的人與完全不用藥的人本質不同」這個問題;校正共變項(第 5→6 列)處理了剩下的可測量差異。 兩者都做,才回到真值附近。
三個設計原則
新使用者設計(new-user design)
只納入開始使用該藥的人,並從第一次處方(加上正確的時間零點)開始追蹤。
不這樣做的話,納入的是盛行使用者(prevalent users)——已經用了一段時間還在用的人。 這群人有兩個問題:他們是「耐受得了這個藥」的倖存者,而且他們的基線特徵已經被藥物本身改變了。
活性對照(active comparator)
拿另一個治療同樣適應症的藥當對照,而不是「沒用藥的人」。
理由在上面的階梯裡看得到:沒用藥的人與用藥的人在疾病嚴重度、就醫行為、共病負擔上都不同, 而那些差異多半沒有被記錄下來。兩群都在用藥的人,至少在「醫師認為需要治療」這件事上是可比的。
時間零點必須明確定義
三件事必須發生在同一個時間點:符合納入條件、分配暴露、開始計算追蹤。
任何一項錯開,就會製造 immortal time bias 或選擇偏誤。這也是目標試驗模擬 存在的理由——它把「如果這是一個隨機試驗,protocol 會怎麼寫」逐項寫出來, 然後檢查觀察性資料的分析有沒有偏離。
RECORD 要求你交代的
RECORD 是 STROBE 的延伸,專門處理常規蒐集資料(routinely collected data)的研究。 除了 STROBE 的項目,它額外要求:
- 資料庫的來源與版本,涵蓋的人口與時間範圍
- 用來定義每個變項的碼與演算法(完整列出,通常放補充材料)
- 這些演算法有沒有驗證研究支持
- 資料清理與串連的過程,以及串連失敗的比例
- 是否可能取得原始病歷做確認
常見誤用
| 誤用 | 為什麼錯 |
|---|---|
| 拿「沒用藥的人」當對照 | 兩群在未測量的特徵上系統性不同;該用活性對照 |
| 納入盛行使用者 | 倖存者偏誤,且基線已被藥物改變 |
| 時間零點與納入、分配不同步 | 製造 immortal time bias |
| 疾病定義沒有驗證依據也不做敏感度分析 | 錯誤分類的方向與大小完全未知 |
| 跨年度趨勢分析不查給付政策沿革 | 政策造成的申報變化與真實趨勢無法分辨(ITS/DiD 是把政策當介入來估的做法) |
| 把校正後的估計當因果 | 沒測到的變項(嚴重度、生活習慣)校正不了 |
| 用藥組回診較密就更容易被診斷,未處理 | 偵測偏誤,會製造出關聯 |
| 只報最終模型不列演算法 | 讀者無法判斷世代是怎麼組出來的,也無法重現 |
| 結果符合預期就不追究方法 | 見上面第 2 列:偏誤互相抵消也會答對 |
重跑本頁的階梯
/opt/homebrew/bin/Rscript figures/scripts/B6-06-target-trial.R讀讀看這張圖
答案取自產生本頁圖表的同一份統計輸出,不是另外打上去的。
階梯表的第 2 列估出來的風險比幾乎正中模擬設定的真值,信賴區間漂亮,p 值也顯著。這一列可以當成好的分析嗎?
看答案與解析
正確答案: 不可以。真值是 0.80,這一列接近它是因為不死時間偏誤剛好與依適應症干擾方向相反、互相抵消
第 2 列的時間零點錯了:追蹤從研究窗打開那一刻起算,而不是從第一次處方起算,等於把「活到能拿到處方」那段依定義不可能發生事件的時間算進暴露組。第 3 列把時鐘釘回處方日,同一份資料就變成 1.34——方向相反。0.78 之所以看起來對,是兩個方向相反的偏誤剛好抵消,而抵消的程度取決於這一份資料的效果大小與干擾強度,換一份就不同,而你不會知道。答案對不代表方法對:一個結果如果只在錯的方法下出現,它就不是證據。
從第 3 列到第 6 列做了兩個修正:換成活性對照、以及校正已測量的共變項。哪一個說法對?
看答案與解析
正確答案: 兩個都需要。換對照組處理的是用藥與完全不用藥的人本質不同,校正處理剩下的可測量差異,兩者都做才回到 0.79
第 4 列的 1.01 說明只靠校正做不到:完全不用藥的那一群在疾病嚴重度、就醫行為與共病負擔上與用藥的人系統性不同,而那些差異多半沒被記錄下來,校正對沒測到的變項無能為力。第 5 列的 0.93 說明只換對照組也不夠:兩群都在用藥的人至少在「醫師認為需要治療」這件事上可比,但剩下的可測量差異還在。兩者都做才得到 0.79,貼近模擬設定的真值。這也是為什麼新使用者設計加活性對照被寫成藥物流行病學的預設起手式,而不是兩個可以擇一的技巧。
階梯表的「分析 n」那一欄每一列都不一樣。為什麼同一份模擬資料會有不同的分析人數?
看答案與解析
正確答案: 因為設計決定了誰被納入。換成活性對照之後只剩 1778 人——只有實際開始使用兩種藥之一的人進得了分析
8000 是整個模擬世代,但沒有一列跑在它身上。第 1 列的 5092 是天真比較納入的人;換成新使用者設計之後納入的人又不同;到了活性對照那幾列只剩 1778,因為對照組從「沒用藥的人」換成「用另一種藥的人」,兩邊的人都被重新定義了。所以分析 n 的變化不是抽樣也不是缺失值,是設計本身在決定誰算數。讀資料庫研究時,看到不同分析的樣本數不一致,第一個要問的就是納入條件哪裡變了,而不是假設有人被漏掉。
第 1 列的天真比較(用藥對沒用藥,不管時序)估出來的風險比方向與真值相反,而且達到統計顯著。這說明什麼?
看答案與解析
正確答案: 說明依適應症干擾可以強到讓方向反轉。1.13 反映的是「醫師把藥開給看起來需要的人」,不是藥的效果
模擬設定裡治療是有保護效果的,而天真比較估出 1.13——方向相反且顯著。原因是暴露與預後之間有典型的依適應症干擾:拿到藥的人本來就比較嚴重。統計顯著在這裡沒有保護作用,它只說明樣本大到能把一個偏誤估得很精確。0.02 這個 p 值正是這件事的樣子:偏誤也可以很顯著。至於對照藥,模擬把它的風險比設定為 1.00,也就是完全沒有效果,所以第三個說法把一個被設定成中性的東西講成有害。
第 6 列(校正共變項)與第 7 列(IPTW)估出來的風險比幾乎一樣。這代表 IPTW 是多餘的嗎?
看答案與解析
正確答案: 不代表。兩種方法用的是同一批已測量的共變項,結果接近只說明在這份資料上它們的假設都成立;0.787 與加權後一致是可信度的訊號
回歸校正與 IPTW 處理的是同一批已測量的共變項,只是走不同的路:一個把共變項放進結果模型,一個用暴露模型算出權重再做加權比較。兩條路在同一份資料上給出 0.787 與 0.785,能推論的是它們的模型設定在這裡都沒有明顯出錯——這是敏感度分析的用法,不是其中一個沒有貢獻。0.931 是未校正的估計,它與這兩個之間的距離量的是校正做了多少事,不能拿來論斷兩種校正方法之間的關係。更重要的是,兩者都只處理有測量到的東西:疾病嚴重度、生活習慣這些健保申報資料裡沒有的變項,加權跟校正一樣救不了。
第 2 列與第 3 列用的是同一群人、同一個模型,只有暴露組追蹤時間的起點不同。這個差異在資料上有多大?
看答案與解析
正確答案: 被錯算進暴露組的不死時間總共 21125 個人月,那段時間依定義不可能發生事件,事件率因此被稀釋
兩列的人與模型完全一樣——870 位新使用者、同樣的對照組、同樣的模型;差的只是暴露組的追蹤從什麼時候開始算。把起點放在研究窗打開那一刻,等於把「活到能拿到第一次處方」那段時間算進暴露組的分母,這裡總共 21125 個人月。分母被灌水而分子不變,暴露組的事件率就被稀釋成看起來有保護效果。至於 3173,那是整個模擬世代的死亡數,它不會因為時鐘放在哪裡而改變——改變的是分母。這就是不死時間偏誤在資料上的樣子:沒有任何一格數字看起來不對,錯的是時間怎麼被算的。
本章用到的統計方法
延伸觀看
Cohort study vs case-control study: everything you need to know in 5min素材來源與授權
本頁為原創內容