9  Chapter 9: 無母數方法 (nonparametric methods)

當資料不想乖乖常態:用排序與重抽樣聽懂它

9.1 本章學習目標

前幾章我們學到 t 檢定、信賴區間與常態近似。這些方法很好用,但醫療資料常常不太乖:住院天數右偏、疼痛分數是等級、樣本數很小、離群值很有存在感。這時候,無母數方法 (nonparametric methods) 提供另一條路。

無母數方法不是「不用假設」的方法,而是較少依賴特定母群體分布形狀的方法。許多非參數檢定使用排序 (rank) 而非原始數值,因此對極端值較穩健。它們像臨床老師看到病人資料很亂時,溫柔但堅定地說:「我們先排隊。」

讀完本章後,你應該能夠:

  1. 說明無母數方法適用的常見情境。
  2. 使用符號檢定 (sign test) 與 Wilcoxon 符號等級檢定 (Wilcoxon signed-rank test) 分析單一樣本或配對資料。
  3. 使用 Mann-Whitney U 檢定 (Mann-Whitney U test) 比較兩個獨立樣本。
  4. 使用 Kruskal-Wallis 檢定 (Kruskal-Wallis test) 比較三組以上獨立樣本。
  5. 使用 Spearman 等級相關 (Spearman rank correlation) 描述單調關係。
  6. 理解置換檢定 (permutation test) 的基本直覺。

9.2 什麼時候考慮無母數方法?

無母數方法常用於下列情境:

  • 樣本數小,難以評估常態假設。
  • 連續資料明顯偏態,例如住院天數、醫療費用、CRP。
  • 有離群值,且離群值不一定是錯誤。
  • 結果變項是次序資料 (ordinal data),例如疼痛分數、疾病嚴重度等級。
  • 研究問題更關心中位數或分布位置,而不是平均值。

不過,無母數方法也不是萬能。它們通常檢定分布位置或排序差異,不一定直接檢定平均值差異。報告結果時,最好搭配中位數、四分位距與合適的效果量,避免只丟出一個 p 值讓讀者自己找路。

9.3 排序的基本概念

許多無母數方法會把原始資料轉成排序。假設資料為 3、8、10,排序分別是 1、2、3。若有相同值,通常使用平均排序。例如 3、8、8、10 中,兩個 8 佔第 2 與第 3 名,因此各給 2.5。

排序的優點是降低極端值影響。若某病人住院 60 天,平均值會被明顯拉高;但在排序資料中,它只是最大值。這不代表離群值不重要,而是無母數方法不讓它一個人把整張桌子掀翻。

9.4 Mann-Whitney U 檢定:兩獨立樣本

Mann-Whitney U 檢定用於比較兩個獨立樣本的分布位置,常被視為兩獨立樣本 t 檢定的非參數替代方法。它也稱 Wilcoxon rank-sum test。

重要提醒:Mann-Whitney U 檢定不只是「中位數檢定」。若兩組分布形狀相似,它可被解讀為位置差異;若分布形狀不同,解釋要更小心。

9.5 範例 1:加強出院準備是否縮短住院天數?

假設研究比較標準照護與加強出院準備兩組病人的住院天數。住院天數右偏且樣本不大,因此考慮 Mann-Whitney U 檢定。

standard_los <- c(3, 4, 4, 5, 5, 6, 7, 8, 10, 13, 18, 25)
enhanced_los <- c(2, 3, 3, 4, 4, 5, 5, 6, 7, 9, 12, 16)

los_df <- data.frame(
  los = c(standard_los, enhanced_los),
  group = c(rep("標準照護", length(standard_los)), rep("加強出院準備", length(enhanced_los))),
  stringsAsFactors = FALSE
)
los_df$group <- factor(los_df$group, levels = c("標準照護", "加強出院準備"))

los_df %>%
  group_by(group) %>%
  summarise(
    count = n(),
    median = median(los),
    mean = mean(los),
    std = sd(los),
    .groups = "drop"
  ) %>%
  mutate(across(c(median, mean, std), ~ round(., 2)))
# A tibble: 2 × 5
  group        count median  mean   std
  <fct>        <int>  <dbl> <dbl> <dbl>
1 標準照護        12    6.5  9     6.65
2 加強出院準備    12    5    6.33  4.14
p1 <- ggplot(los_df, aes(x = group, y = los, fill = group)) +
  geom_boxplot(alpha = 0.7, show.legend = FALSE) +
  geom_jitter(color = "#333333", alpha = 0.7, width = 0.12, height = 0) +
  scale_fill_brewer(palette = "Set2") +
  labs(
    title = "右偏住院天數:兩組比較",
    x = "照護組別",
    y = "住院天數"
  )

p1
Figure 9.1: 右偏住院天數的兩組比較。每個點代表一位病人。
# 執行 Wilcoxon rank-sum test (Mann-Whitney U test)
mw_result <- wilcox.test(enhanced_los, standard_los, alternative = "less", exact = FALSE)

mw_test_df <- data.frame(
  quantity = c("U 統計量", "單尾 p 值"),
  value = c(as.numeric(mw_result$statistic), mw_result$p.value),
  stringsAsFactors = FALSE
)
mw_test_df$value <- round(mw_test_df$value, 4)

mw_test_df
   quantity   value
1  U 統計量 52.0000
2 單尾 p 值  0.1288

這裡使用單尾對立假設,因為研究問題是「加強出院準備是否縮短住院天數」。若研究前沒有明確方向,應使用雙尾檢定。

9.6 符號檢定與 Wilcoxon 符號等級檢定

配對資料若差值明顯不符合常態,或結果是次序尺度,可以考慮符號檢定或 Wilcoxon 符號等級檢定。

符號檢定只看差值方向:改善、惡化或無變化。它非常穩健,但也丟掉很多資訊。Wilcoxon 符號等級檢定同時考慮差值方向與大小排序,因此通常比符號檢定更有檢定力,但它假設差值分布大致對稱。

9.7 範例 2:治療前後疼痛分數

某疼痛門診記錄 12 位病人治療前後的疼痛分數,分數為 0 到 10 的次序量尺。研究問題是治療後疼痛是否下降。

pain_before <- c(8, 7, 6, 8, 9, 7, 6, 8, 7, 9, 6, 8)
pain_after <- c(5, 6, 4, 6, 6, 5, 5, 7, 4, 7, 4, 6)
paired_df <- data.frame(id = 1:12, before = pain_before, after = pain_after)
paired_df$difference <- paired_df$after - paired_df$before

paired_df
   id before after difference
1   1      8     5         -3
2   2      7     6         -1
3   3      6     4         -2
4   4      8     6         -2
5   5      9     6         -3
6   6      7     5         -2
7   7      6     5         -1
8   8      8     7         -1
9   9      7     4         -3
10 10      9     7         -2
11 11      6     4         -2
12 12      8     6         -2
p2 <- ggplot(paired_df, aes(x = difference)) +
  geom_histogram(breaks = seq(-5.5, 1.5, by = 1), fill = "#8ab17d", color = "white") +
  geom_vline(xintercept = 0, color = "#d62828", linetype = "dashed", linewidth = 1) +
  labs(
    title = "配對差值分布",
    x = "疼痛分數差值:治療後 - 治療前",
    y = "人數"
  )

p2
Figure 9.2: 治療後與治療前疼痛分數差值分布。負值代表疼痛下降。
wilcoxon_result <- wilcox.test(pain_after, pain_before, paired = TRUE, alternative = "less", exact = FALSE)

wilcoxon_test_df <- data.frame(
  quantity = c("Wilcoxon 統計量", "單尾 p 值", "差值中位數"),
  value = c(as.numeric(wilcoxon_result$statistic), wilcoxon_result$p.value, median(paired_df$difference)),
  stringsAsFactors = FALSE
)
wilcoxon_test_df$value <- round(wilcoxon_test_df$value, 4)

wilcoxon_test_df
         quantity   value
1 Wilcoxon 統計量  0.0000
2       單尾 p 值  0.0011
3      差值中位數 -2.0000

如果 p 值小,代表資料提供證據支持治療後疼痛分數下降。臨床上仍應報告下降幅度,例如差值中位數與四分位距。病人關心的不是 p 值多小,而是疼痛少了多少。

9.8 Kruskal-Wallis 檢定:三組以上比較

Kruskal-Wallis 檢定是 Mann-Whitney U 檢定的多組延伸,用於比較三組以上獨立樣本的分布位置。它常被視為單因子 ANOVA 的非參數替代方法。

虛無假設是各組來自相同分布。若檢定顯著,代表至少一組不同,但不會告訴你哪兩組不同。後續需要事後比較,並注意多重比較問題。

9.9 範例 3:三種劑量下的 CRP

dose_a <- c(9, 12, 14, 15, 18, 21, 25, 31)
dose_b <- c(7, 9, 10, 12, 14, 18, 20, 23)
dose_c <- c(5, 6, 8, 9, 10, 12, 14, 16)

crp_df <- data.frame(
  crp = c(dose_a, dose_b, dose_c),
  dose = c(rep("低劑量", length(dose_a)), rep("中劑量", length(dose_b)), rep("高劑量", length(dose_c))),
  stringsAsFactors = FALSE
)
crp_df$dose <- factor(crp_df$dose, levels = c("低劑量", "中劑量", "高劑量"))

crp_df %>%
  group_by(dose) %>%
  summarise(
    count = n(),
    median = median(crp),
    mean = mean(crp),
    .groups = "drop"
  ) %>%
  mutate(across(c(median, mean), ~ round(., 2)))
# A tibble: 3 × 4
  dose   count median  mean
  <fct>  <int>  <dbl> <dbl>
1 低劑量     8   16.5  18.1
2 中劑量     8   13    14.1
3 高劑量     8    9.5  10  
p3 <- ggplot(crp_df, aes(x = dose, y = crp, fill = dose)) +
  geom_boxplot(alpha = 0.7, show.legend = FALSE) +
  geom_jitter(color = "#333333", alpha = 0.7, width = 0.12, height = 0) +
  scale_fill_brewer(palette = "Set3") +
  labs(
    title = "三組 CRP 分布",
    x = "治療劑量",
    y = "CRP (mg/L)"
  )

p3
Figure 9.3: 三種治療劑量下的 CRP 分布。
kruskal_result <- kruskal.test(list(dose_a, dose_b, dose_c))

kruskal_test_df <- data.frame(
  quantity = c("H 統計量", "p 值"),
  value = c(as.numeric(kruskal_result$statistic), kruskal_result$p.value),
  stringsAsFactors = FALSE
)
kruskal_test_df$value <- round(kruskal_test_df$value, 4)

kruskal_test_df
  quantity  value
1 H 統計量 6.1965
2     p 值 0.0451

若結果顯著,下一步應該做組間事後比較,並控制多重比較造成的第一型錯誤增加。本章先保留這個伏筆,因為多組推論會在後面章節更完整處理。

9.10 Spearman 等級相關

Pearson 相關衡量線性關係,而 Spearman 等級相關衡量單調關係 (monotonic relationship)。如果一個變項增加時另一個變項大致增加或大致減少,即使不是直線,Spearman 相關仍可能捕捉到。

Spearman 相關會先把資料轉成排序,再計算排序間的相關。因此它對離群值較不敏感,也適合次序資料。

9.11 範例 4:身體活動分數與 HbA1c

假設一組糖尿病病人有身體活動分數與 HbA1c。活動分數越高,HbA1c 看起來越低,但關係不一定線性。

activity <- c(1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 8, 9, 10, 11, 12)
hba1c <- c(9.8, 9.4, 9.1, 8.9, 8.7, 8.4, 8.1, 7.9, 7.6, 7.4, 7.2, 7.1, 6.9, 6.8, 6.7)
corr_df <- data.frame(activity_score = activity, hba1c = hba1c)

head(corr_df)
  activity_score hba1c
1              1   9.8
2              2   9.4
3              2   9.1
4              3   8.9
5              4   8.7
6              4   8.4
p4 <- ggplot(corr_df, aes(x = activity_score, y = hba1c)) +
  geom_point(size = 3, color = "#457b9d", alpha = 0.8) +
  geom_smooth(method = "loess", se = FALSE, color = "#d62828", linewidth = 1.2) +
  labs(
    title = "Spearman 相關:單調關係",
    x = "身體活動分數",
    y = "HbA1c (%)"
  )

p4
Figure 9.4: 身體活動分數與 HbA1c 的單調關係。紅線為 LOWESS 平滑線。
spearman_result <- cor.test(activity, hba1c, method = "spearman", exact = FALSE)

spearman_test_df <- data.frame(
  quantity = c("Spearman rho", "p 值"),
  value = c(as.numeric(spearman_result$estimate), spearman_result$p.value),
  stringsAsFactors = FALSE
)
spearman_test_df$value <- round(spearman_test_df$value, 4)

spearman_test_df
      quantity   value
1 Spearman rho -0.9973
2         p 值  0.0000

相關不等於因果。活動量高與 HbA1c 低可能有關,但也可能受到飲食、藥物順從性、病程長短與社經因素影響。Spearman 相關能描述關係,但不能替代研究設計。

9.12 置換檢定的直覺

置換檢定是一種重抽樣方法。其核心想法是:若虛無假設下兩組沒有差異,那麼組別標籤應該可以任意交換。每次隨機重新分配標籤並計算統計量,就能建立虛無假設下的參考分布。

置換檢定的優點是直覺清楚,且不需要強烈分布假設。缺點是計算量較大,不過現代電腦通常不是問題。請注意,置換檢定仍依賴交換性 (exchangeability):在虛無假設下,資料標籤可以交換才合理。

median_difference <- function(x, y) {
  median(x) - median(y)
}

set.seed(20260627)
observed_diff <- median_difference(enhanced_los, standard_los)

combined <- c(enhanced_los, standard_los)
n_enhanced <- length(enhanced_los)
n_total <- length(combined)

perm_diffs <- replicate(5000, {
  permuted <- sample(combined)
  median_difference(permuted[1:n_enhanced], permuted[(n_enhanced + 1):n_total])
})

perm_pvalue <- (sum(perm_diffs <= observed_diff) + 1) / (5000 + 1)

perm_test_df <- data.frame(
  quantity = c("觀察到的中位數差", "置換檢定 p 值"),
  value = c(observed_diff, perm_pvalue),
  stringsAsFactors = FALSE
)
perm_test_df$value <- round(perm_test_df$value, 4)

perm_test_df
          quantity   value
1 觀察到的中位數差 -1.5000
2    置換檢定 p 值  0.2807

置換檢定很適合教學,因為它把「如果沒有組間差異,結果會長什麼樣子」這件事具體化。它也提醒我們,統計檢定本質上是在建立一個虛無世界,然後看現實資料在那個世界裡有多不尋常。

9.13 常見陷阱

  1. 以為非參數等於沒有假設:無母數方法仍有資料結構與抽樣假設。
  2. 把 Mann-Whitney U 一律解釋為中位數差異:只有在分布形狀相似時較合理。
  3. 忽略配對結構:配對資料應分析差值或使用配對方法。
  4. 只報 p 值:仍應報告中位數、四分位距或效果量。
  5. 多組檢定顯著後不做適當事後比較:Kruskal-Wallis 只告訴你至少一組不同。
  6. 把相關當因果:Spearman 相關只描述單調關係。

9.14 本章重點整理

  • 無母數方法較少依賴特定母群體分布,常用於偏態、小樣本或次序資料。
  • Mann-Whitney U 檢定用於兩獨立樣本的排序比較。
  • Wilcoxon 符號等級檢定用於配對資料或單一樣本中位數相關問題。
  • Kruskal-Wallis 檢定用於三組以上獨立樣本比較。
  • Spearman 等級相關描述兩變項的單調關係。
  • 置換檢定透過重新排列標籤建立虛無分布。
  • 無母數方法也需要搭配圖形、摘要統計與臨床解釋。

9.15 小練習

  1. 某研究比較兩組住院費用,資料明顯右偏,你會考慮哪一種檢定?為什麼?
  2. 若同一批病人治療前後疼痛分數為次序尺度,應使用獨立樣本方法還是配對方法?
  3. Kruskal-Wallis 檢定顯著後,為何不能直接知道哪兩組不同?
  4. Spearman 相關與 Pearson 相關的主要差異是什麼?
  5. 用自己的話說明置換檢定的虛無分布如何產生。
practice_group_a <- c(12, 14, 15, 18, 22, 40)
practice_group_b <- c(8, 9, 11, 12, 13, 18)
practice_mw <- wilcox.test(practice_group_b, practice_group_a, alternative = "less", exact = FALSE)

practice_before <- c(6, 7, 8, 7, 9, 6)
practice_after <- c(5, 5, 6, 6, 7, 5)
practice_wilcoxon <- wilcox.test(practice_after, practice_before, paired = TRUE, alternative = "less", exact = FALSE)

practice_results <- data.frame(
  檢定 = c("Mann-Whitney U", "Wilcoxon signed-rank"),
  統計量 = c(as.numeric(practice_mw$statistic), as.numeric(practice_wilcoxon$statistic)),
  `p 值` = c(practice_mw$p.value, practice_wilcoxon$p.value),
  check.names = FALSE,
  stringsAsFactors = FALSE
)
practice_results$統計量 <- round(practice_results$統計量, 4)
practice_results$`p 值` <- round(practice_results$`p 值`, 4)

practice_results
                  檢定 統計量   p 值
1       Mann-Whitney U      5 0.0223
2 Wilcoxon signed-rank      0 0.0160

9.16 Glossary

中文術語 English term 說明
無母數方法 nonparametric methods 較少依賴特定母群體分布形式的統計方法。
排序 rank 將觀察值依大小轉換為名次。
次序資料 ordinal data 有自然順序但間距未必相等的資料。
Mann-Whitney U 檢定 Mann-Whitney U test 比較兩獨立樣本排序分布的非參數檢定。
Wilcoxon rank-sum test Wilcoxon rank-sum test Mann-Whitney U 檢定的另一名稱。
符號檢定 sign test 只使用差值方向進行推論的非參數檢定。
Wilcoxon 符號等級檢定 Wilcoxon signed-rank test 使用配對差值方向與大小排序的非參數檢定。
Kruskal-Wallis 檢定 Kruskal-Wallis test 比較三組以上獨立樣本排序分布的非參數檢定。
Spearman 等級相關 Spearman rank correlation 基於排序衡量兩變項單調關係的相關係數。
單調關係 monotonic relationship 一變項增加時另一變項大致持續增加或減少的關係。
置換檢定 permutation test 透過重新排列標籤建立虛無分布的重抽樣檢定。
交換性 exchangeability 在虛無假設下觀察值標籤可交換的性質。
事後比較 post-hoc comparison 多組整體檢定後進一步比較特定組別的方法。
多重比較 multiple comparisons 同時進行多個比較而增加第一型錯誤風險的情況。