t 檢定與變異數分析
t 檢定的常態性假設到底假設了什麼、為什麼 Welch 該當預設、配對與獨立差在哪、ANOVA 之後的多重比較,以及為什麼「先做常態性檢定再決定」是個壞習慣。
這個方法在解決什麼問題
你有一個連續的結果(出生體重、血壓、住院天數)和一個分組變項。問題永遠是同一句話:組間看到的這個差距,大到不像是抽樣的運氣嗎?
t 檢定與變異數分析(analysis of variance, ANOVA)是同一個想法的兩種規模。它們都在算同一個比值:
t 檢定的分母是差距的標準誤,ANOVA 的分母是組內變異。分子被分母除掉之後,你得到的是「以這份資料的雜訊為尺,這個差距有幾個單位大」。p 值只是把那個數字換算成機率的最後一步。
本頁用 MASS::birthwt:1986 年美國麻州 Springfield 一家醫院收集的 189 位產婦資料,結果變項是新生兒出生體重(公克)。
常態性假設到底假設了什麼
這個假設常被壓縮成一句「t 檢定不假設資料常態」,但它其實有三層,混在一起講就會出錯:
- 精確推論那一層確實是對資料的假設。 小樣本下 t 統計量精確服從 t 分布,前提是每組的觀測值(更精確地說是模型的誤差項)確實常態;實務上資料只是近似常態,所以那個分布也只是近似。配對 t 檢定假設的則是配對差值近似常態,不是兩次測量各自常態。
- Welch 放寬的不是這一層。 Welch t 檢定鬆綁的是「兩組變異數相等」這個假設,常態性假設它原封不動地留著。
- 樣本夠大時這層假設才變得沒那麼要緊。 觀測值彼此獨立、分布的變異數有限時,中央極限定理(central limit theorem, CLT)讓平均數(或平均差)的抽樣分布趨近常態,因此原始資料的輕中度偏態通常不致命。但小樣本、極端離群值、或非常重尾的分布仍會讓推論失準。
換句話說,真正該問的不是「資料常不常態」,而是「以我手上的 n 與這個分布的形狀,常態近似夠不夠好」。第三層可以實際演給你看:拿 survival::pbc 的血清膽紅素(偏態係數 2.7,右尾長到不行)重複抽樣,看樣本平均數的分布怎麼靠向常態:
figures/scripts/B1-02-t-test-anova.R| 抽樣單位 | 分布的偏態係數 |
|---|---|
| 原始資料(每一個病人) | 2.7 |
| n = 5 的樣本平均數 | 1.18 |
| n = 30 的樣本平均數 | 0.47 |
| n = 60 的樣本平均數 | 0.37 |
所以實務上的判準不是「跑一次常態性檢定看它顯不顯著」,而是:
- n 很小(每組十幾人以下)而且分布明顯偏態 → t 檢定的 p 值可能不準,考慮無母數方法或以差異的信賴區間為主。
- n 中等以上(每組數十人) → 即使原始資料偏態,t 檢定通常相當穩健。
- 有極端離群值 → 這才是真正危險的情況。CLT 對離群值的收斂比對偏態慢得多,而且平均數本身可能已經不是你想要的摘要量。
Welch 應該是預設
R 的 t.test() 預設 var.equal = FALSE,也就是 Welch t 檢定,這是對的。Student’s t 檢定多要求一個條件——兩組變異數相同——而這個條件:
- 在真實資料裡幾乎不會剛好成立;
- 用檢定(
var.test()、Levene 檢定)去驗它,會落入本頁第七節講的同一個陷阱; - 不成立時 Student 版本的型一錯誤率會偏掉,特別是在兩組樣本數不等的時候。
而 Welch 不需要這個條件,代價只是自由度變成小數、檢定力損失極小。不等變異數才是常見情況,等變異數是特例——所以預設值應該對應常見情況,而不是特例。
以本頁的資料為例,兩組變異數比是 1.3,兩種算法的結論其實一樣:
| t | df | p | 差距的 95% CI(公克) | |
|---|---|---|---|---|
| Welch(預設) | 2.73 | 170.1 | 0.007 | 79–489 |
| Student(等變異數) | 2.65 | 187 | 0.009 | 73–495 |
差異很小,這正是重點:用 Welch 幾乎沒有成本,卻少了一個要辯護的假設。 沒有理由為了省那一點檢定力去承擔它。
動手跑一次
library(MASS)
data(birthwt, package = "MASS")
birthwt$smoke_f <- factor(birthwt$smoke, levels = c(0, 1),
labels = c("Non-smoker", "Smoker"))
birthwt$race_f <- factor(birthwt$race, levels = 1:3,
labels = c("White", "Black", "Other"))
# 兩組獨立樣本:Welch(預設)
t.test(bwt ~ smoke_f, data = birthwt)
# 配對:同一批人量兩次
# R 4.4 起公式介面不再接受 paired=TRUE(會報 cannot use 'paired' in formula method)
data(sleep)
t.test(Pair(sleep$extra[sleep$group == 2],
sleep$extra[sleep$group == 1]) ~ 1)
# 三組以上:單因子 ANOVA + Tukey 事後比較
fit <- aov(bwt ~ race_f, data = birthwt)
summary(fit)
TukeyHSD(fit)
# 無母數的對應版本(分布嚴重偏態且 n 小時)
wilcox.test(bwt ~ smoke_f, data = birthwt) # Mann-Whitney U
kruskal.test(bwt ~ race_f, data = birthwt) # Kruskal-Wallis驗證環境:R 4.6.0 + MASS 7.3.65。t.test() 預設就是 Welch,不要為了「跟教科書一樣」去加 var.equal = TRUE。
import statsmodels.api as sm
from scipy import stats
import pingouin as pg
bw = sm.datasets.get_rdataset("birthwt", "MASS").data
g1 = bw.loc[bw["smoke"] == 0, "bwt"]
g2 = bw.loc[bw["smoke"] == 1, "bwt"]
# ⚠️ scipy 的預設與 R 相反,Welch 要自己開
stats.ttest_ind(g1, g2, equal_var=False)
sleep = sm.datasets.get_rdataset("sleep").data
d1 = sleep.loc[sleep["group"] == 1, "extra"].to_numpy()
d2 = sleep.loc[sleep["group"] == 2, "extra"].to_numpy()
stats.ttest_rel(d2, d1)
groups = [g["bwt"].to_numpy() for _, g in bw.groupby("race")]
stats.f_oneway(*groups)
pg.pairwise_tukey(data=bw, dv="bwt", between="race")scipy 的 ttest_ind 預設 equal_var=True,與 R 相反——要 Welch 必須顯式寫 equal_var=False。
figures/scripts/B1-02-t-test-anova.R抽菸組 74 人、平均 2771.9 g(SD 659.6),未抽菸組 115 人、平均 3055.7 g(SD 752.7)。差距 283.8 g,95% CI 79–489 g,p = 0.007,Cohen’s d = 0.4。
配對與獨立:同一批數字,兩個結論
配對(paired)與獨立(independent)的差別不在資料長什麼樣,而在這兩欄數字之間有沒有一對一的連結:同一個人前後測、同一個人左右眼、配對設計的病例對照。有連結就必須用配對版本,理由是配對把「人與人之間的差異」整個消掉,剩下的雜訊小得多。
用 Student 在 1908 年分析的那份安眠藥資料(datasets::sleep,10 位受試者各試兩種藥,資料由 Cushny 與 Peebles 收集)示範。兩種分析法吃的是完全相同的 20 個數字:
| 分析方式 | 平均差(小時) | 95% CI | t | df | p |
|---|---|---|---|---|---|
| 配對 t 檢定(正確) | 1.58 | 0.70–2.46 | 4.06 | 9 | 0.003 |
| 獨立樣本 t 檢定(錯誤) | 1.58 | -0.21–3.37 | 1.86 | 17.8 | 0.079 |
點估計一模一樣,p 值卻從 0.003 變成 0.079。原因是兩次測量的相關係數高達 0.8——本來就睡得多的人兩種藥都睡得多。配對分析把這個個人差異扣掉,只看每個人自己的變化(差值的 SD 只有 1.23,而各組原始 SD 是 1.79 與 2)。
figures/scripts/B1-02-t-test-anova.R左圖那幾條線就是配對檢定在看的東西。10 位受試者裡,9 位在第二種藥上睡得比較多、0 位比較少、1 位完全沒變。這些線在垂直方向占據 -1.6 到 5.5 小時,人與人差得很開,但每一條線自己的走向幾乎一致——而走向這件事,只有把兩個點連起來才看得見。獨立樣本分析把兩欄拆開,看到的是兩堆上下散得很開的點(SD 1.79 與 2),那個共同走向被算進雜訊裡;配對分析先把每條線壓成一個差值(右圖),差值從 0 到 4.6,散布只剩 SD 1.23,而它們的平均 1.58 小時的 95% 信賴區間 0.70–2.46 整段都在 0 的右邊。同一個走向,在一種分析裡是訊號,在另一種裡是雜訊。
ANOVA 與它之後的多重比較
三組以上時,直接做三次兩兩 t 檢定會讓型一錯誤累積:三次獨立比較至少出現一次假陽性的機率是 14.3%,十次就是 40.1%。ANOVA 用一個綜合檢定(omnibus test)先問一句「這幾組的平均數全部相同嗎」,把多重性擋在門外。
本頁三個族群分組的結果是 F(2, 186) = 4.91,p = 0.008, = 0.05——也就是說族群這個變項解釋了出生體重總變異的 5%。
Tukey HSD 是最常用的事後方法,它調整的是家族層級(family-wise)的錯誤率:
| 比較 | 平均差(g) | Tukey 95% CI | 調整後 p | 未調整 p |
|---|---|---|---|---|
| 黑人 vs 白人 | -383 | -756.2 到 -9.8 | 0.043 | 0.012 |
| 其他 vs 白人 | -297.4 | -566.2 到 -28.7 | 0.026 | 0.011 |
| 其他 vs 黑人 | 85.6 | -304.5 到 475.6 | 0.862 | 0.579 |
最後兩欄的差距就是調整的代價:黑人 vs 白人的未調整 p 是 0.012,調整後變成 0.043,剛好貼著 0.05。論文只報未調整的兩兩 p 值而不說明,等於默默把型一錯誤率放大。
幾個實務要點:
- 事後比較要事先講好。 「所有兩兩比較」與「只比對照組」需要的調整不同(後者用 Dunnett 檢定力更好)。
- 不要用「先看 ANOVA 顯不顯著再決定要不要做兩兩比較」當作免調整的理由(俗稱 Fisher’s LSD)。組數超過三組時它保護不了家族錯誤率。
- 主要假說如果本來就是特定兩組,就直接做那一個比較並事先寫進計畫書,不必先跑 ANOVA。
為什麼「先做常態性檢定再決定」是壞習慣
很多人的流程是:先跑 Shapiro-Wilk,p > 0.05 就用 t 檢定、p < 0.05 就改 Wilcoxon。這個流程有三個問題,其中第一個最致命。
常態性檢定的檢定力隨 n 變動,方向剛好跟你需要的相反。 從一個固定的偏態分布(Gamma(shape = 2, rate = 1), skewness = 1.41)重複抽樣 2000 次:
| 每組樣本數 | Shapiro-Wilk 判為「不常態」的比例 | Welch t 檢定的實際型一錯誤率 |
|---|---|---|
| n = 20 | 52.4% | 0.052 |
| n = 500 | 100.0% | 0.050 |
同一個分布,n = 20 時 Shapiro 只抓到 52.4%,將近一半的樣本被放行、於是你用了 t 檢定;n = 500 時抓到 100.0%,於是每次都改用無母數。但 Welch 的實際型一錯誤率在兩種情況下都貼著名目的 0.05——這個流程在該擔心的時候放行,在不必擔心的時候攔阻。
另外兩個問題:
- 兩階段流程本身會扭曲最終的錯誤率。 你報出來的 p 值是「條件在第一個檢定的結果之上」算的,它的分布已經不是原來那個了。
- 它把方法選擇交給資料。 該用什麼分析應該由設計與問題決定並事先寫下來,不是跑完看結果再挑。
正確的做法:事先根據變項的性質決定(住院天數、費用、生物標記濃度這類本來就右偏的量,一開始就規劃用中位數與無母數方法或轉換),再用直方圖與 Q-Q 圖確認資料沒有意料之外的形狀,不用檢定當開關。
常見誤用
| 誤用 | 為什麼錯 |
|---|---|
| 先跑常態性檢定再決定用不用 t 檢定 | 檢定力隨 n 走向與需求相反,且兩階段流程扭曲最終錯誤率 |
為了「符合教科書」指定 var.equal = TRUE | 等變異數才是特例;Welch 少一個假設而幾乎不損檢定力 |
| 同一批人前後測卻用獨立樣本 t 檢定 | 丟掉配對帶來的變異縮減,本頁例子 p 從 0.003 變 0.079 |
| 三組以上做三次兩兩 t 檢定不調整 | 家族錯誤率升到 14.3%,十次比較則是 40.1% |
| 只報 p 值不報差距與信賴區間 | 讀者無法判斷差距的臨床意義,也看不出精確度 |
| 綜合檢定顯著就宣稱「各組都不同」 | F 只說「不全相同」;誰跟誰不同要看事後比較 |
| 嚴重右偏的變項照樣比平均數 | 型一錯誤率可能沒問題,但平均數本身已不是有意義的摘要 |
| p > 0.05 就說「兩組沒有差異」 | 只能說本研究未偵測到差異;要主張相等需要等效性設計與預設的界限 |
| 把 ANOVA 的 小當成「檢定錯了」 | 顯著與解釋力是兩件事,兩個都要報 |
重跑本頁的所有數字
/opt/homebrew/bin/Rscript figures/scripts/B1-02-t-test-anova.R讀讀看這張圖
答案取自產生本頁圖表的同一份統計輸出,不是另外打上去的。
同一份安眠藥資料,兩種分析吃的是完全相同的 20 個數字,點估計都是 1.58 小時,配對 t 檢定的 p 是 0.0028,獨立樣本 t 檢定是 0.0794。差別是從哪裡來的?
看答案與解析
正確答案: 配對分析檢定的是每個人自己的差值,那一欄的標準差只有 1.23 小時,人與人之間的差異被整個扣掉了
兩種分析的點估計一模一樣,變的只有雜訊從哪裡來。原始的兩欄各自散得很開(第二種藥那一欄的標準差是 2.00 小時),而本來就睡得多的人兩種藥都睡得多——相關係數 0.80 說的就是這件事。配對分析先把每個人壓成一個差值,那一欄的標準差只剩 1.23,於是共同走向從雜訊變成訊號。相關高不是「算了兩次」,恰恰相反:正因為相關高,忽略配對才會白白把檢定力丟掉。而第二種藥那一欄的標準差比較大也不是療效不穩定,那個散布主要是人與人的差異,不是藥的差異。反過來把獨立資料硬當配對做同樣是錯的,而且更難被發現,因為它會憑空製造出檢定力。
審稿人要求「先檢定兩組變異數是否相等,相等再用 Student t 檢定」。本頁抽菸與不抽菸的出生體重比較,兩組變異數比是 1.3。該怎麼回應?
看答案與解析
正確答案: Welch 的 p 是 0.007,與 Student 版本幾乎一樣——Welch 少一個要辯護的假設而檢定力損失極小
兩種算法在這份資料上結論一樣(0.007 對 0.009),而那正是重點:用 Welch 幾乎沒有成本,卻少了一個要辯護的假設。變異數檢定的 p 是 0.225,看起來像是「通過了」,但用檢定當開關會落入與常態性檢定同一個陷阱——它的檢定力隨 n 走,小樣本時該擔心的情況會被放行,而小樣本、兩組人數不等,正是 Student 版本的型一錯誤率最容易偏掉的時候。至於「結論一樣所以哪個當預設沒差」,預設值應該對應常見情況:真實資料裡兩組變異數幾乎不會剛好相等,等變異數才是特例。
從同一個右偏分布重複抽樣:每組 20 人時 Shapiro-Wilk 判為不常態的比例是 52.4%,每組 500 人時是 100%。這對「先檢定常態性再決定用什麼檢定」這個流程說了什麼?
看答案與解析
正確答案: n = 500 時 Welch 的實際型一錯誤率仍是 0.050,貼著名目水準——這個流程在該擔心的時候放行,在不必擔心的時候攔阻
小樣本才是常態近似可能不夠好的時候,而 Shapiro-Wilk 在 n = 20 時將近一半的樣本被放行;大樣本時中央極限定理讓平均數的抽樣分布已經很接近常態,它卻幾乎每次都攔下來,比例是 1.000。Welch 的實際型一錯誤率兩邊都貼著名目水準:0.052 與 0.050,那個 0.052 是模擬的抽樣波動,不是超標的證據。所以真正該問的不是「資料常不常態」,而是「以我手上的 n 與這個分布的形狀,常態近似夠不夠好」,而且要事先依變項的性質決定。兩階段流程還有第二個問題:你報出來的 p 值是條件在第一個檢定結果之上算的,它的分布已經不是原來那個了。
三個族群的出生體重比較,綜合 F 檢定 p = 0.0083。Tukey 表上黑人對白人那一列的未調整 p 是 0.0117、調整後是 0.0428。該報哪一個?
看答案與解析
正確答案: 報 0.0428——它把同時做了三個比較這件事算了進去
調整後的 0.0428 剛好貼著慣用水準,而未調整的 0.0117 看起來從容得多,最後兩欄的差距就是調整的代價。「綜合檢定顯著就不必再調整」是 Fisher’s LSD 的說法,組數超過三組時它保護不了家族錯誤率,何況三次獨立比較至少出現一次假陽性的機率就已經有 14.3%。0.8624 是另外一組比較調整後的 p 值,它不代表整組的錯誤率——Tukey 是對每一個比較各自放寬門檻,不是取最大值。實務上還有兩件事:事後比較要事先講好(「所有兩兩比較」與「只比對照組」需要的調整不同),而主要假說本來就是特定兩組時,直接做那一個比較並寫進計畫書,不必先跑綜合檢定。
族群這個變項的綜合 F 檢定是顯著的,同一段報表上還印著 eta 平方。要判斷族群對出生體重的影響有多大,該看哪一個?
看答案與解析
正確答案: 看 eta 平方 0.05。族群只解釋了總變異的一小部分
F 值 4.91 與 p 值 0.01 都同時編碼了效應大小與樣本數:效應很小的時候,只要 n 夠大,F 照樣可以很大,所以它不是效應量。eta 平方 0.05 才是——族群這個變項解釋了出生體重總變異的一小部分,其餘絕大多數的變異來自別的地方。顯著的 F 只說「這幾組的平均數不全相同」,既不說是誰跟誰不同(那要事後比較),也不說差得有沒有臨床意義(那要看效應量與差距的信賴區間)。只報 p 值而不報差距與信賴區間,讀者無從判斷臨床意義,也看不出精確度。
抽菸與不抽菸的新生兒平均體重差是 283.8 公克,論文只寫了「p = 0.007,抽菸組顯著較輕」。要判斷這個差距有沒有臨床意義,還缺哪一個數字?
看答案與解析
正確答案: 缺差距的 95% 信賴區間下界 79 公克——它回答這份資料容許的最小差距是多少
p 值只說「這個差距大到不像是抽樣運氣」,它不說差多少。點估計 283.8 公克是最可能的答案,但判斷臨床意義時要看區間能拉到多小:下界是 79 公克。如果 79 公克在你的情境下已經沒有臨床意義,那這個顯著結果就不足以支持任何決定。抽菸組的 74 個人是這個區間寬度的成因之一,但人數本身不是效應量;不抽菸組的平均 3056 公克是基準線,同樣不回答「差距最小可能是多少」。反過來說,未達顯著時也只能寫「本研究未偵測到差異」,要主張兩組相當需要等效性設計與事先設定的界限。
用到這個方法的章節
延伸觀看
醫學統計 EP10 t 檢定與非參數法
醫學統計 EP11 ANOVA
醫學統計 EP04 標準差與標準誤
生物統計學一 45.【型一與型二錯誤】素材來源與授權
本頁為原創內容