Functional Enrichment

Step 04 / 05

ORA(과대표집 분석)와 GSEA(순위기반)를 이용해 GO/KEGG/MSigDB 경로를 해석합니다. (DEG 결과 또는 전체 유전자 순위를 입력)


A) 준비물 (패키지 설치)

처음 한 번만 설치.


if (!requireNamespace("BiocManager", quietly=TRUE)) install.packages("BiocManager")
BiocManager::install(c(
  "clusterProfiler", "org.Hs.eg.db", "enrichplot",
  "DOSE", "msigdbr", "fgsea", "pathview"
))
# 시각화
install.packages(c("ggplot2", "dplyr", "tibble", "readr"))

B) 입력 데이터 준비 (ID 매핑)

ORA는 DEG 목록(예: adj.P<0.05 & |logFC|≥1)과 배경(universe)이 필요합니다. GSEA는 전체 유전자 순위(예: t 통계량 또는 logFC×-log10P)가 필요합니다.


library(dplyr); library(tibble); library(AnnotationDbi); library(org.Hs.eg.db)

# 1) DEG 테이블 불러오기 (Step 03 출력)
deg <- read.csv("DEG_with_annotation.csv")   # 열: PROBEID, SYMBOL, logFC, adj.P.Val 등

# 2) DEG 필터
deg_sig <- deg %>% filter(adj.P.Val < 0.05, abs(logFC) >= 1)

# 3) SYMBOL → ENTREZ (clusterProfiler는 ENTREZ 사용 권장)
map <- AnnotationDbi::select(org.Hs.eg.db,
                             keys = unique(deg$SYMBOL),
                             columns = c("ENTREZID","SYMBOL"),
                             keytype = "SYMBOL") %>% distinct(SYMBOL, .keep_all = TRUE)

deg_sig_entrez <- map$ENTREZID[match(deg_sig$SYMBOL, map$SYMBOL)] %>% na.omit()
universe_entrez <- map$ENTREZID[match(deg$SYMBOL, map$SYMBOL)] %>% na.omit()

length(deg_sig_entrez); length(universe_entrez)

C) ORA — GO/KEGG

과대표집 검정. DEG setuniverse를 명확히 지정하는 것이 중요합니다.


library(clusterProfiler); library(enrichplot); library(org.Hs.eg.db)
library(ggplot2)

# GO Biological Process
ego <- enrichGO(gene          = deg_sig_entrez,
                universe      = universe_entrez,
                OrgDb         = org.Hs.eg.db,
                keyType       = "ENTREZID",
                ont           = "BP",
                pAdjustMethod = "BH",
                pvalueCutoff  = 0.05,
                qvalueCutoff  = 0.05)

# KEGG
ekegg <- enrichKEGG(gene         = deg_sig_entrez,
                    universe     = universe_entrez,
                    organism     = "hsa",
                    pvalueCutoff = 0.05)

# 결과 저장
write.csv(as.data.frame(ego),   "ORA_GO_BP.csv", row.names=FALSE)
write.csv(as.data.frame(ekegg), "ORA_KEGG.csv",  row.names=FALSE)

# 시각화 예시
dotplot(ego, showCategory=15) + ggtitle("GO BP ORA")
barplot(ekegg, showCategory=15) + ggtitle("KEGG ORA")

# 네트워크/개념도 예시(복수 유전자 연결)
cnetplot(ego, categorySize="pvalue", showCategory=8)

D) MSigDB gene sets 가져오기

msigdbrH(Hallmark), C2(Canonical pathways) 등 선택 가능(인간: species = "Homo sapiens").


library(msigdbr); library(dplyr)

m_df <- msigdbr(species = "Homo sapiens", category = "H")  # Hallmark
msig_h <- m_df %>% select(gs_name, entrez_gene)

# ORA용 리스트로 변환
msig_list <- split(msig_h$entrez_gene, msig_h$gs_name)
length(msig_list); head(names(msig_list))

E) GSEA — fgsea (pre-ranked)

전체 유전자 순위 벡터(named numeric) 필요. 이름=ENTREZ, 값=순위점수(예: limma t 통계).


library(fgsea); library(dplyr)

# 1) 전체 순위 만들기 (limma 결과 'tt' 사용 예시)
tt <- read.csv("DEG_limma_results.csv")  # coef 1 결과 등
# SYMBOL→ENTREZ 매핑
map <- AnnotationDbi::select(org.Hs.eg.db, keys=tt$PROBEID,
                             columns=c("ENTREZID","SYMBOL"), keytype="PROBEID")
tt2 <- tt %>% mutate(PROBEID = rownames(tt)) %>% left_join(map, by="PROBEID")

# 순위점수: t 또는 logFC * -log10(P.Value) 등
tt2 <- tt2 %>% filter(!is.na(ENTREZID)) %>% distinct(ENTREZID, .keep_all=TRUE)
ranks <- tt2$t; names(ranks) <- tt2$ENTREZID
ranks <- sort(ranks, decreasing=TRUE)

# 2) fgsea 실행 (MSigDB Hallmark 예)
fg <- fgsea(pathways = msig_list, stats = ranks, nperm = 10000)
fg <- fg %>% arrange(padj)
write.csv(fg, "GSEA_fgsea_Hallmark.csv", row.names=FALSE)

# 3) 시각화
plotEnrichment(msig_list[["HALLMARK_INTERFERON_GAMMA_RESPONSE"]], ranks)
fgsea::plotGseaTable(msig_list[head(fg$pathway, 5)], ranks, fg, gseaParam=1)

F) (선택) KEGG pathway 도식

pathview로 KEGG 경로에 발현 변화를 색으로 표시.


library(pathview)

# fold change 이름=ENTREZ
fc <- tt2$logFC; names(fc) <- tt2$ENTREZID
# 예: hsa04630 (JAK-STAT)
pathview(gene.data = fc, pathway.id = "hsa04630", species = "hsa", out.suffix="example")

G) 팁 & 주의

실무 포인트
  • Universe를 명확히: 동일 플랫폼/필터링 후 분석에 실제 사용 가능한 유전자 집합을 배경으로 사용.
  • ORA: DEG 컷오프에 민감. 컷이 너무 빡세면 경로 검출력이 줄어듭니다.
  • GSEA: 컷오프 없이 순위 전체를 쓰므로, 미세 변화가 집단적으로 쌓인 경로 탐지에 유리.
  • MSigDB는 컬렉션별 해석이 다릅니다. H(Hallmark)는 요약형, C2는 canonical pathway 위주.
  • ID 타입 혼용 주의(SYMBOL/ENTREZ/ENSEMBL). 하나를 기준으로 통일하고 매핑 로그를 남기세요.
요약
  • ORA는 DEG set + universe, GSEA는 전체 순위로 접근 — 두 방법은 상호보완적입니다.
  • clusterProfiler/enrichplot로 GO·KEGG를, msigdbr/fgsea로 MSigDB·GSEA를 빠르게 수행할 수 있습니다.
  • 결과는 padj(FDR) 기준으로 해석하며, 상위 항목을 시각화(dotplot, cnetplot, enrichment plot)로 요약하세요.