先用 10 個基因手算一次 Running ES,再看一張 5,000 個基因的真實尺度富集圖,最後學會怎麼判讀 NES、FDR 和 Leading-edge。
GSEA 的全名是 Gene Set Enrichment Analysis(基因集富集分析)。ORA 的全名是 Over-Representation Analysis(過度代表性分析),一般說的「GO / KEGG 富集分析」多半就是 ORA。
ORA 會先用 padj < 0.05、|log2FC| > 1 這類門檻切出 DEG 清單,再看通路成員是否在清單裡過多。GSEA 不設門檻,而是把所有基因依差異指標排序,再問整個基因集是否集體往排序榜的某一端靠攏。
ORA 問的是:顯著基因清單中屬於某條通路的基因,是否比隨機抽樣預期的還多?它用超幾何檢定(hypergeometric test,相當於單尾的 Fisher's exact test)檢查下面這張 2×2 表。
| 在通路中 | 不在通路中 | 合計 | |
|---|---|---|---|
| 顯著基因(DEG) | k | n − k | n |
| 非顯著基因 | K − k | N − K − n + k | N − n |
| 合計 | K | N − K | N |
N 是背景基因總數(universe),K 是通路的基因數,n 是 DEG 數,k 是兩者重疊的基因數。p 值是「從 N 個基因隨機抽 n 個,抽中至少 k 個通路成員」的機率:
常見報表中的 GeneRatio = k/n,BgRatio = K/N。如果 GeneRatio 明顯大於 BgRatio,就表示這條通路在 DEG 中過度出現。
| ORA(Over-Representation Analysis,門檻法) | GSEA(Gene Set Enrichment Analysis,排序法) | |
|---|---|---|
| 輸入 | DEG 清單(離散) | 全基因排序榜 L(連續) |
| 門檻 | 必須設定,結果對門檻很敏感 | 不需要 |
| 擅長捕捉 | 少數劇烈變化的基因 | 很多基因微幅但方向一致的變化 |
| 方向性 | 通常需上調、下調分開跑 | NES 正負直接給出方向 |
| 統計檢定 | 超幾何檢定 / Fisher's exact test | Running-sum ES + 置換檢定 |
| 代價 | 快、簡單 | 需要置換檢定,依賴完整表現資料 |
| 常用工具 | clusterProfiler enrichGO / enrichKEGG、DAVID、g:Profiler、Enrichr | GSEA 桌面版、fgsea、clusterProfiler gseGO |
Hallmark(MSigDB Collection H)從 MSigDB 數千條彼此重疊的基因集中,歸納出 50 條代表性強、重疊少的基因集,每條代表一個明確的生物狀態或過程。第一輪分析先跑這 50 條,多重檢定的負擔小,結果也比較容易聚焦。
.gct 與 .cls。stat,或 sign(log2FC) × −log10(p)。不建議只用 log2FC,因為它不考慮變異度。榜單依 r 由大到小排序,重複的基因符號要先合併。h.all.v2024.1.Hs.symbols.gmt(版本號以下載時為準)。通常只保留在資料中有 15–500 個成員的基因集。這條基因集有 200 個基因,代表「細胞完成 DNA 複製後、進入有絲分裂前」的檢查點與分裂機器,例如 Cyclin B–CDK1 複合體、啟動分裂的 PLK1 與 AURKA、DNA 損傷時踩煞車的 CHEK1、負責去磷酸化活化 CDK1 的 CDC25 家族,以及紡錘體組裝檢查點的 BUB1、MAD2L1、CDC20。
| 情境 | 預期 NES | 生物學解讀 |
|---|---|---|
| 腫瘤 vs 正常組織 | 正(+) | 細胞增殖旺盛,進入 M 期的細胞多,分裂相關基因整體上調 |
| CDK4/6 抑制劑 vs DMSO | 負(−) | 細胞停在 G1,進不了 G2/M,這群基因整體下調 |
| 處理與細胞週期無關 | ≈ 0,不顯著 | 成員散佈在榜單各處,沒有集體偏向 |
情境:腫瘤 vs 正常組織。下表 10 個基因已依排序指標 ri 由高到低排好。G2M 基因集在這 10 個基因中只有 3 個成員:PLK1、CDK1、CHEK1(綠色標記),其餘 7 個是非成員(低氧、糖解、細胞外基質、代謝相關)。
← 圖可左右滑動 →
| Rank | 基因 | 屬於 S? | ri | 這一步 | Running ES |
|---|
點任一列可把該基因加入或移出基因集,圖和數字會即時重算。按「重設」回到 PLK1 / CDK1 / CHEK1。
| Rank | 基因 | ri | 加 / 扣分 | Running ES(分數) | 小數 | |
|---|---|---|---|---|---|---|
| 1 | VEGFA | Miss | +2.5 | −1/7 | −1/7 | −0.1429 |
| 2 | PLK1 | Hit | +2.0 | +2.0/3.2 = +5/8 | −1/7 + 5/8 = 27/56 | +0.4821 |
| 3 | LDHA | Miss | +1.5 | −1/7 | 19/56 | +0.3393 |
| 4 | CDK1 | Hit | +1.0 | +1.0/3.2 = +5/16 | 73/112(峰值) | +0.6518 |
| 5 | SLC2A1 | Miss | +0.5 | −1/7 | 57/112 | +0.5089 |
| 6 | CHEK1 | Hit | −0.2 | +|−0.2|/3.2 = +1/16 | 57/112 + 7/112 = 4/7 | +0.5714 |
| 7 | COL1A1 | Miss | −0.8 | −1/7 | 3/7 | +0.4286 |
| 8 | CD36 | Miss | −1.2 | −1/7 | 2/7 | +0.2857 |
| 9 | ALB | Miss | −1.8 | −1/7 | 1/7 | +0.1429 |
| 10 | PPARG | Miss | −2.4 | −1/7 | 0 | 0.0000 |
為什麼最後一定回到 0:所有 Hit 的加分總和 = (2.0 + 1.0 + 0.2) / 3.2 = 1;所有 Miss 的扣分總和 = 7 × 1/7 = 1。兩者相減必為 0。
結果:ES = +73/112 ≈ +0.6518,峰值在 Rank 4(CDK1)。正值表示 G2M 成員偏向榜單頂端,也就是在腫瘤中上調。
Leading-edge:正向富集時取 Rank 1 到峰值之間的成員,所以是 PLK1、CDK1。CHEK1 雖然是成員,但位在峰值之後,而且 r 為 −0.2,對 ES 沒有貢獻,不屬於 Leading-edge。
把同樣的規則放大到 5,000 個基因、200 個 G2M 成員,就是 GSEA 論文常見的三層圖。以下是依三種情境模擬的資料。統計量在你的瀏覽器裡用 1,000 次 gene-set 置換即時算出。游標移到圖上可以看到每個位置的數值。
← 圖可左右滑動 →
| 圖層 | 內容 | 看什麼 |
|---|---|---|
| 上層:Running ES 曲線 | 由左走到右的累計分數 | 峰值在左、高於 0 代表正富集;谷值在右、低於 0 代表負富集。峰越尖、越靠邊,代表成員越集中在榜單一端。 |
| 中層:條碼 | 每條直線是一個成員基因的位置 | 條碼在左側密集代表上調,在右側密集代表下調,均勻散開代表沒有偏向。綠色底色是 Leading-edge 範圍。 |
| 下層:排序指標 | 全基因的 ri 分佈 | 左邊高於 0 是處理組較高,右邊低於 0 是對照組較高。零交叉點是上調與下調的分水嶺。 |
| 指標 | 意義 | 常用門檻 |
|---|---|---|
| ES | Running ES 偏離 0 的最大值 | 不直接比較(會受基因集大小影響) |
| NES | ES ÷ 同號置換 ES 的平均值,可跨基因集比較 | |NES| > 1.5 算強(經驗值);正負代表方向 |
| Nominal p | 單一基因集的置換 p 值,未做多重校正 | 只作參考 |
| FDR q | 依所有基因集的 NES 虛無分佈估計偽陽性比例 | < 0.25 探索性(GSEA 官方建議);< 0.05 嚴謹發表 |
| FWER p | 最保守的整體錯誤率 | < 0.05 時結論非常穩 |
# DESeq2 結果 res 已備妥(Tumor vs Normal),並已加上基因符號欄 symbol
library(msigdbr); library(fgsea); library(dplyr)
# msigdbr 10 版起,完整資料在另一個套件 msigdbdf,第一次用要先安裝
h <- msigdbr(species = "Homo sapiens", collection = "H") # 舊版用 category = "H"
pw <- split(h$gene_symbol, h$gs_name)
rk <- res |> as.data.frame() |> filter(!is.na(stat), !is.na(symbol)) |>
group_by(symbol) |> summarise(stat = mean(stat)) # 重複基因合併
ranks <- sort(setNames(rk$stat, rk$symbol), decreasing = TRUE)
set.seed(42)
fg <- fgsea(pw, ranks, minSize = 15, maxSize = 500)
fg |> arrange(padj) |> select(pathway, NES, padj, size) |> head(10)
plotEnrichment(pw[["HALLMARK_G2M_CHECKPOINT"]], ranks) +
ggplot2::labs(title = "HALLMARK_G2M_CHECKPOINT")
fg$leadingEdge[[which(fg$pathway == "HALLMARK_G2M_CHECKPOINT")]]
fgsea 的 padj 是 Benjamini–Hochberg 校正後的 p 值,與 GSEA 桌面版的 FDR q 算法不同,但用途相同。使用 GSEA 桌面版時,建議設定:Permutations 1000、Enrichment statistic weighted、Metric Signal2Noise、Max/Min size 500/15。
| 主題 | 常見誤解 | 正確說法 |
|---|---|---|
| ES 的定義 | ES = argmax |Phit − Pmiss| | argmax 回傳的是位置。ES 是 Running ES 偏離 0 最大的那個數值,並保留正負號;位置則是峰(谷)所在的 rank。 |
| NES | ES 除以所有置換 ES 的平均值 | 除以同號置換 ES 的平均值:正 ES 用正的虛無值,負 ES 用負的虛無值(取絕對值)。 |
| FDR | GSEA 的 FDR 就是 Benjamini–Hochberg | GSEA 原始 FDR 是用所有基因集的 NES 虛無分佈直接估計,不是 BH;BH 是 fgsea、clusterProfiler 的做法。 |
| Leading-edge | 基因集的成員都是 Leading-edge | 只有排在峰值之前(正富集)或谷值之後(負富集)的成員才是。像第 4 節的 CHEK1 就不是。 |
| Hallmark 數量 | 有些條目重複或共用代碼 | Hallmark 共 50 條,彼此不重複;名稱都以 HALLMARK_ 開頭,例如 HALLMARK_PEROXISOME 與 HALLMARK_SPERMATOGENESIS 是兩條不同的基因集。 |