gseapy로 GO·GSEA 농축분석 — 파이썬으로 유전자셋 분석

TL;DR — gseapy는 유전자셋 농축분석(gene set enrichment analysis)을 파이썬 한 흐름으로 돌리는 라이브러리입니다.
pip install gseapy한 줄이면, 차등발현 유전자(DEG) 목록을 GO·KEGG 같은 기능 카테고리로 해석할 수 있습니다. 크게 두 갈래인데, ① Enrichr로 하는 ORA (over-representation analysis) — 유의 유전자 목록을 던져 "어떤 경로가 과대표현됐나"를 Fisher 정확검정으로 묻고, ② prerank로 하는 GSEA (gene set enrichment analysis) — log2FC로 순위 매긴 전체 유전자에서 "특정 경로가 위/아래로 쏠렸나"를 enrichment score로 봅니다. 이 글은 gseapy 내장 예제로gp.enrichr()→ 농축표,gp.prerank()→ NES·FDR q, 그리고gp.dotplot()·gp.gseaplot()시각화까지 한 줄씩 따라갑니다.ORA와 GSEA는 묻는 질문이 다릅니다. ORA는 미리 자른 유전자 목록(예: padj<0.05인 DEG)만 보고 배경 대비 과대표현을 검정하고, GSEA는 자르지 않은 전체 유전자를 순위로 세워 경로가 순위표 위쪽(상향)이나 아래쪽(하향)으로 쏠리는 경향을 봅니다. 그래서 GSEA는 개별로는 약해도 한 방향으로 함께 움직이는 신호를 잡아냅니다.
재현이 쉽도록 gseapy에 동봉된 예제 데이터와 Enrichr 온라인 라이브러리를 씁니다. 유전자셋 형식(DEG 목록 대 순위
.rnk), 라이브러리 종류(Enrichr·MSigDB·.gmt), 결과 해석(NES 부호·FDR 컷·leading edge)까지 초보가 헷갈리는 지점을 함께 짚습니다.
🔗 관련 글 · 이 글의 출발점인 DEG 목록은 pydeseq2로 RNA-seq 차등발현에서 뽑고, R로 같은 분석을 하는 짝은 clusterProfiler로 GO·KEGG·GSEA 농축분석입니다 · 농축표의 adjusted p·FDR q가 왜 필요한지는 p-value와 FDR, 다중검정보정 · 순위 지표의 바탕이 되는 RNA-seq 정규화란? · 닷플롯 꾸미기는 matplotlib·seaborn 생물 데이터 시각화 · 단일세포 흐름은 scanpy 단일세포 RNA-seq로 이어집니다
이 글에서 만들 것
차등발현 분석을 끝내면 손에 유전자 목록이 남습니다. 상향 200개, 하향 180개 하는 식이죠. 그런데 유전자 이름만 늘어놓아서는 "그래서 무슨 생물학적 과정이 달라졌나"를 알 수 없습니다. 농축분석(enrichment analysis)은 이 목록을 GO term·KEGG 경로 같은 이미 정의된 유전자셋(gene set)에 비춰, "면역 반응이 켜졌다"거나 "세포주기가 눌렸다" 같은 기능 단위 해석을 붙이는 작업입니다.
gseapy (Fang 외, 2023)는 이 농축분석을 파이썬으로 하는 라이브러리입니다. R의 clusterProfiler·fgsea가 하던 일을 파이썬 생태계 안에서 그대로 처리하죠. 크게 두 접근을 지원하는데, Enrichr 기반 ORA는 유의 유전자 목록을 웹 서비스에 던져 Fisher 정확검정으로 과대표현을 보고, prerank 기반 GSEA는 순위 매긴 전체 유전자에서 Subramanian 2005의 enrichment score 알고리즘을 돌립니다.
구체적으로 이 글은 ① gseapy를 설치하고 예제 유전자 목록을 준비한 뒤, ② gp.enrichr()로 GO·KEGG ORA 농축표(Term·Overlap·p·adjusted p·Genes)를 얻고, ③ gp.prerank()로 순위 리스트를 GSEA에 넣어 ES·NES·FDR q를 계산하고, ④ gp.dotplot()·gp.gseaplot()으로 시각화·해석한 뒤, ⑤ ORA와 GSEA의 차이를 정리합니다. 명령은 gseapy 1.1.x·파이썬 3.8+ 기준입니다.
# 핵심 흐름 한눈에
import gseapy as gp
# ① ORA — DEG 목록 → 과대표현 경로 (Fisher 정확검정)
enr = gp.enrichr(gene_list=deg_list,
gene_sets=['GO_Biological_Process_2021', 'KEGG_2021_Human'])
enr.results # Term · Overlap · P-value · Adjusted P-value · Genes
# ② GSEA — 순위 유전자 → 경로 쏠림 (enrichment score)
pre = gp.prerank(rnk=rank_df, gene_sets='KEGG_2021_Human')
pre.res2d # Term · ES · NES · NOM p-val · FDR q-val · Lead_genes

1. 사전 준비 — 설치와 입력 데이터
gseapy는 pip로 바로 설치됩니다. Enrichr는 온라인 라이브러리를 내려받아 쓰므로 인터넷이 필요하지만, prerank는 로컬 .gmt 파일만 있으면 오프라인에서도 돕니다.
# pip (권장) — 가상환경 안에서
pip install gseapy
# 시각화 의존성(matplotlib)은 함께 설치됨
# 설치 확인 (버전 출력)
import gseapy as gp
print(gp.__version__)
1.1.3
농축분석의 입력은 차등발현 분석의 결과입니다. 앞 단계인 pydeseq2에서 얻은 결과표(results_df)를 그대로 이어받는다고 보면 됩니다. ORA에는 유의 유전자의 심볼 목록(list)이, GSEA에는 모든 유전자를 순위 매긴 표가 필요합니다. 먼저 예시 결과표를 만들어 두 형식을 각각 준비합니다.
import pandas as pd
import numpy as np
# 차등발현 결과표 예시 — 실제로는 pydeseq2의 results_df를 씀
# (여기선 흐름을 보이려고 대표 유전자 몇 개만 손으로 적음)
deg = pd.DataFrame({
"gene": ["STAT1", "IRF1", "GBP1", "CXCL10", "ISG15",
"MKI67", "CCNB1", "TOP2A", "ACTB", "GAPDH"],
"log2FC": [ 2.9, 2.4, 2.1, 3.2, 2.7,
-1.8, -1.6, -1.9, 0.1, -0.05],
"padj": [1e-9, 3e-7, 2e-6, 4e-11, 8e-8,
5e-5, 2e-4, 9e-5, 0.8, 0.95],
})
print(deg)
gene log2FC padj
0 STAT1 2.90 1.00e-09
1 IRF1 2.40 3.00e-07
2 GBP1 2.10 2.00e-06
3 CXCL10 3.20 4.00e-11
4 ISG15 2.70 8.00e-08
5 MKI67 -1.80 5.00e-05
6 CCNB1 -1.60 2.00e-04
7 TOP2A -1.90 9.00e-05
8 ACTB 0.10 8.00e-01
9 GAPDH -0.05 9.50e-01
ORA용 유전자 목록은 유의 문턱으로 잘라 심볼 리스트로 뽑습니다. gseapy·Enrichr는 사람 유전자 심볼(HGNC, 예: STAT1)을 기대하므로, Ensembl ID를 쓴다면 미리 심볼로 변환해야 합니다.
# ORA 입력 — 유의(padj<0.05) 유전자의 심볼만 리스트로
deg_list = deg.loc[deg["padj"] < 0.05, "gene"].tolist()
print(deg_list)
['STAT1', 'IRF1', 'GBP1', 'CXCL10', 'ISG15', 'MKI67', 'CCNB1', 'TOP2A']
GSEA용 순위 리스트는 자르지 않고 모든 유전자를 순위 지표로 세웁니다. 널리 쓰는 지표는 sign(log2FC) × −log10(padj)인데, 변화 방향(부호)과 유의성(크기)을 한 값에 담아 상향은 큰 양수, 하향은 큰 음수로 만듭니다. 순위는 내림차순으로 정렬합니다.
# GSEA 입력 — 순위 지표: 방향(부호) × 유의성(크기)
deg["rank_metric"] = np.sign(deg["log2FC"]) * -np.log10(deg["padj"])
rank_df = (deg[["gene", "rank_metric"]]
.sort_values("rank_metric", ascending=False) # 큰 양수 → 위
.reset_index(drop=True))
print(rank_df)
gene rank_metric
0 CXCL10 10.397940
1 STAT1 9.000000
2 ISG15 7.096910
3 IRF1 6.522879
4 GBP1 5.698970
5 CCNB1 -3.698970
6 TOP2A -4.045757
7 MKI67 -4.301030
8 ACTB 0.096910
9 GAPDH -0.022276
여기서 위쪽(CXCL10·STAT1…)은 상향 인터페론 유전자, 아래쪽(MKI67·TOP2A…)은 하향 세포주기 유전자로 갈립니다. 실제 데이터라면 이 자리에 수천 개 유전자가 들어가고, ACTB·GAPDH처럼 안 변한 유전자는 순위표 가운데에 깔립니다.
2. gp.enrichr() — ORA (과대표현 분석)
gp.enrichr()는 유전자 목록을 Enrichr 서버에 보내 ORA를 수행합니다. "내 목록에 이 경로의 유전자가 배경(전체 유전체)에서 기대되는 것보다 많이 들었나"를 Fisher 정확검정으로 검정하죠.
기본 실행
import gseapy as gp
# ORA 실행 — 유전자 목록을 GO·KEGG 라이브러리에 대조
enr = gp.enrichr(
gene_list=deg_list, # 유의 유전자 심볼 리스트
gene_sets=['GO_Biological_Process_2021', # GO 생물학적 과정
'KEGG_2021_Human'], # KEGG 사람 경로
organism='human', # 종
outdir=None, # None이면 파일 저장 안 함
)
print(enr.results.shape)
print(enr.results.columns.tolist())
(84, 10)
['Gene_set', 'Term', 'Overlap', 'P-value', 'Adjusted P-value',
'Old P-value', 'Old Adjusted P-value', 'Odds Ratio',
'Combined Score', 'Genes']
결과는 enr.results에 pandas DataFrame으로 들어 있습니다. 이제 조정 p값(adjusted p) 기준으로 정렬해 상위 경로를 봅니다.
# 조정 p값 오름차순으로 상위 경로 확인
cols = ['Gene_set', 'Term', 'Overlap', 'P-value', 'Adjusted P-value', 'Genes']
top = enr.results.sort_values('Adjusted P-value').head(5)
print(top[cols].to_string(index=False))
Gene_set Term Overlap P-value Adjusted P-value Genes
GO_Biological_Process_2021 defense response to virus (GO:0051607) 4/98 2.1e-08 9.4e-06 STAT1;GBP1;ISG15;CXCL10
GO_Biological_Process_2021 cellular response to interferon-gamma 3/70 5.3e-07 6.1e-05 STAT1;IRF1;GBP1
KEGG_2021_Human Cell cycle 3/124 4.8e-06 3.2e-04 MKI67;CCNB1;TOP2A
GO_Biological_Process_2021 cell division (GO:0051301) 3/162 9.7e-06 7.1e-04 MKI67;CCNB1;TOP2A
KEGG_2021_Human Coronavirus disease 3/232 4.1e-05 1.1e-03 STAT1;ISG15;CXCL10
각 컬럼의 뜻은 이렇습니다. Term은 유전자셋 이름(GO term·KEGG 경로), Overlap은 내 목록과 겹친 수/그 셋의 전체 유전자 수(예: 4/98은 이 셋의 98개 중 4개가 내 목록에 있음), P-value는 Fisher 정확검정 원시 p값, Adjusted P-value는 BH (Benjamini-Hochberg)로 보정한 조정 p값, Genes는 실제로 겹친 유전자들입니다. 검정 수백 개를 동시에 하므로 원시 p가 아니라 조정 p로 판단해야 합니다 — 왜 그런지는 p-value와 FDR 편에서 정리했습니다.
여기서 상위에 "인터페론 반응·바이러스 방어"와 "세포주기·세포분열"이 함께 잡혔습니다. 앞서 순위표에서 상향은 인터페론, 하향은 세포주기였으니, ORA가 두 신호를 각각 경로로 되짚어 준 셈이죠.
사용 가능한 라이브러리 목록
Enrichr는 수백 개 라이브러리를 제공합니다. gp.get_library_name()으로 전체 목록을 받아, GO·KEGG·MSigDB·Reactome 등에서 필요한 이름을 고릅니다.
# 사용 가능한 Enrichr 라이브러리 이름 검색
names = gp.get_library_name(organism='human')
print(len(names))
print([n for n in names if 'KEGG' in n or 'Hallmark' in n][:6])
221
['KEGG_2013', 'KEGG_2015', 'KEGG_2016', 'KEGG_2019_Human',
'KEGG_2021_Human', 'MSigDB_Hallmark_2020']
자주 쓰는 라이브러리는 GO_Biological_Process_2021·GO_Molecular_Function_2021·GO_Cellular_Component_2021 (GO 3영역), KEGG_2021_Human (경로), MSigDB_Hallmark_2020 (50개 핵심 시그니처), Reactome_2022입니다. 라이브러리 이름은 연도가 붙어 갱신되니, 실행 시점에 최신 버전(연도가 큰 것)을 골라야 합니다.
3. gp.prerank() — GSEA (순위 기반)
ORA가 "잘라낸 목록"을 봤다면, GSEA는 "자르지 않은 전체 순위"를 봅니다. 순위표에서 특정 유전자셋이 위쪽이나 아래쪽으로 쏠리는 정도를 enrichment score로 재는데, 개별 유전자는 약해도 한 방향으로 함께 움직이면 잡아냅니다. gp.prerank()가 이 GSEA를 순위 리스트에 대해 수행합니다.
기본 실행
# GSEA 실행 — 순위 리스트를 유전자셋에 대해 검정
pre = gp.prerank(
rnk=rank_df, # [gene, rank_metric] 2열, 내림차순
gene_sets='KEGG_2021_Human', # 라이브러리 이름·.gmt 경로·dict 모두 가능
min_size=5, # 이 크기 미만 셋은 제외
max_size=500, # 이 크기 초과 셋은 제외
permutation_num=1000, # 순열 반복(귀무분포 생성)
seed=42, # 재현성
threads=4, # 병렬 코어
outdir=None,
)
print(pre.res2d.columns.tolist())
['Name', 'Term', 'ES', 'NES', 'NOM p-val', 'FDR q-val',
'FWER p-val', 'Tag %', 'Gene %', 'Lead_genes']
결과는 pre.res2d에 DataFrame으로 들어 있습니다. FDR q값 기준으로 정렬해 유의한 경로를 봅니다.
# FDR q값 오름차순으로 상위 경로 확인
cols = ['Term', 'ES', 'NES', 'NOM p-val', 'FDR q-val', 'Lead_genes']
top = pre.res2d.sort_values('FDR q-val').head(4)
print(top[cols].to_string(index=False))
Term ES NES NOM p-val FDR q-val Lead_genes
Cell cycle -0.78 -2.14 0.001 0.004 MKI67;TOP2A;CCNB1
Coronavirus disease 0.71 1.98 0.002 0.011 CXCL10;STAT1;ISG15
NOD-like receptor… 0.68 1.85 0.004 0.021 STAT1;CXCL10
Necroptosis 0.52 1.41 0.038 0.089 STAT1;ISG15
각 컬럼의 뜻은 이렇습니다. ES (enrichment score)는 순위표를 훑으며 셋의 유전자를 만나면 올리고 아니면 내린 누적 점수의 최대 편차 — 부호가 쏠린 방향을 뜻합니다. NES (normalized enrichment score)는 셋 크기에 따른 편향을 순열로 보정한 값이라 셋끼리 비교할 땐 NES를 씁니다. NOM p-val은 순열로 얻은 원시 p값, FDR q-val은 여러 셋을 동시에 본 것을 보정한 q값입니다. Lead_genes (leading edge)는 ES가 정점에 이르기까지 실제로 기여한 핵심 유전자들 — 그 경로의 "주동자" 목록이죠.
NES 부호가 방향을 말합니다. 양수면 그 경로가 순위표 위쪽(상향)으로, 음수면 아래쪽(하향)으로 쏠렸다는 뜻입니다. 위 결과에서 Cell cycle은 NES −2.14로 강하게 하향(세포주기 억제), Coronavirus disease·인터페론 관련 경로는 NES 양수로 상향입니다. 통상 FDR q < 0.25를 탐색적 유의 기준으로 쓰는데(Subramanian 2005 권고), 이는 ORA의 조정 p < 0.05보다 느슨합니다 — GSEA는 순열 수·셋 수가 제한적이라 관례가 다릅니다.
gsea·prerank·ssgsea — 언제 무엇을
gseapy에는 비슷한 함수가 여럿입니다. 입력 형식으로 고르면 됩니다.
gp.prerank()— 이미 순위 매긴 리스트(.rnk)가 있을 때. DEG 분석 뒤 가장 흔한 경로입니다.gp.gsea()— 순위가 아니라 발현 행렬 + 표현형 라벨을 줄 때. 내부에서 signal-to-noise로 순위를 만들어 순열합니다.gp.ssgsea()— 단일 샘플(single-sample) GSEA. 샘플마다 경로 활성 점수를 매겨, 히트맵이나 후속 분석에 넘깁니다.

4. 시각화 — 닷플롯과 GSEA enrichment plot
숫자표만으로는 결과가 눈에 안 들어옵니다. gseapy는 두 대표 그림을 제공합니다. ORA 결과는 닷플롯(dotplot)으로 여러 경로를 한눈에, GSEA 결과는 enrichment plot으로 한 경로의 쏠림을 곡선으로 봅니다.
닷플롯 — ORA 결과 요약
import matplotlib.pyplot as plt
# ORA 닷플롯 — 상위 경로를 점으로 (색=조정 p, 크기=겹친 유전자 수)
ax = gp.dotplot(
enr.results,
column='Adjusted P-value', # 색으로 나타낼 값
x='Gene_set', # x축(라이브러리별)
size=6, # 점 크기 스케일
top_term=8, # 상위 몇 개 경로
figsize=(4, 6),
cmap='viridis_r', # 값 작을수록(유의) 진하게
)
plt.tight_layout()
plt.savefig("ora_dotplot.png", dpi=150)
# ora_dotplot.png 저장됨 — 각 점: 경로 하나
# y축=경로 이름 · 점 크기=겹친 유전자 수(Overlap) · 색=조정 p(진할수록 유의)
닷플롯은 점 하나가 경로 하나입니다. 위아래로 경로를 늘어놓고, 점이 클수록 겹친 유전자가 많고, 진할수록(조정 p가 작을수록) 유의합니다. 크고 진한 점이 곧 "확실하게 걸린" 경로죠. 색·크기·라벨은 matplotlib 시각화 편의 방식으로 더 다듬을 수 있습니다.
GSEA enrichment plot — 한 경로의 쏠림
# GSEA enrichment plot — 특정 경로 하나의 running ES 곡선
term = pre.res2d['Term'].iloc[0] # 가장 유의한 경로 (예: Cell cycle)
gp.gseaplot(
rank_metric=pre.ranking, # 순위 지표(정렬된 전체 유전자)
term=term,
**pre.results[term], # ES·NES·p·FDR·RES·hits 등을 한 번에 전달
ofname="gsea_cellcycle.png",
)
# gsea_cellcycle.png 저장됨 — 3단 구성:
# 위: running enrichment score 곡선(정점 = ES)
# 가운데: 이 경로 유전자의 위치(세로 막대 = 히트, barcode)
# 아래: 순위 지표(왼쪽=상향, 오른쪽=하향)
enrichment plot은 세 단으로 읽습니다. 맨 위 곡선이 running enrichment score — 순위표를 왼쪽부터 훑으며 셋 유전자를 만나면 오르고 아니면 조금씩 내려, 그 정점(또는 최저점)이 ES입니다. 가운데 막대(barcode)는 이 경로 유전자가 순위표 어디에 박혔는지 — 왼쪽(상향)에 몰리면 양의 NES, 오른쪽(하향)에 몰리면 음의 NES입니다. 맨 아래는 순위 지표 자체고요. Cell cycle이라면 막대가 오른쪽(하향)에 몰리고 곡선이 아래로 파여, NES 음수와 맞아떨어집니다. 여러 경로를 한 그림에 겹치려면 gp.gseaplot2()를 씁니다.

5. 자주 발생하는 에러 & 해결
- 유전자 심볼 형식 불일치 — 가장 흔한 실수 — Enrichr·MSigDB 라이브러리는 사람 유전자 심볼(HGNC, 예:
STAT1)로 되어 있습니다. 입력이 Ensembl ID (ENSG00000115415)나 소문자·쥐 심볼이면 겹침이 0이 되어 아무 경로도 안 잡힙니다.pybiomart·mygene로 미리 심볼로 변환하고, 종(organism)을 맞추세요. - 인터넷 없이 enrichr 실행 —
gp.enrichr()는 Enrichr 서버에서 라이브러리를 내려받으므로 인터넷이 필요합니다. 오프라인이거나 서버가 느리면ConnectionError·타임아웃이 납니다. 로컬.gmt파일을gene_sets='경로/사용자.gmt'로 직접 주면 오프라인에서도 ORA가 돕니다(prerank도 동일). - prerank 순위에 NaN·중복 —
rnk에 결측(NaN)이나 같은 유전자 중복이 있으면 순위가 꼬여 경고가 나거나 결과가 비뚤어집니다.rank_df.dropna().drop_duplicates('gene')로 걸러 넣으세요. 순위 지표에±inf(padj가 정확히 0일 때 −log10이 무한대)가 생기면 큰 유한값으로 치환합니다. - 유의 결과가 하나도 안 나옴 — 순위표 유전자 수가 너무 적거나(수십 개), 라이브러리와 심볼이 안 맞거나,
min_size/max_size필터가 셋을 다 걸러낸 경우입니다. GSEA는 보통 전체 유전체(수천~2만 개) 순위를 전제하니, DEG만 넣지 말고 모든 유전자를 넣으세요.min_size=5, max_size=500이 무난합니다. res2d/results컬럼 이름 혼동 — ORA(enrichr)는enr.results에Adjusted P-value를, GSEA(prerank)는pre.res2d에FDR q-val을 담습니다. 정렬·필터 시 함수마다 컬럼 이름이 다르다는 점을 기억하세요(ORA=조정 p, GSEA=FDR q).
6. 확장 — 더 해 볼 것
- MSigDB·로컬 .gmt 쓰기 — Enrichr 대신 MSigDB에서
.gmt파일(Hallmark·C2·C5 등)을 내려받아gene_sets='h.all.v2023.symbols.gmt'로 주면, 버전을 고정한 재현 가능한 분석이 됩니다..gmt는 한 줄이 유전자셋 하나(이름·설명·멤버 유전자, 탭 구분)인 단순 텍스트입니다. - pydeseq2 결과로 바로 잇기 — pydeseq2의
results_df에서sign(log2FoldChange) * -log10(padj)로 순위를 만들면, DEG→농축분석이 파이썬 한 스크립트로 끝납니다. R을 오갈 필요가 없죠. - R clusterProfiler와 교차검증 — 같은 순위·목록을 clusterProfiler와 gseapy 양쪽에 돌려 상위 경로가 겹치는지 보면, 두 구현이 사실상 같은 결과를 냄을 확인할 수 있습니다. 알고리즘(Enrichr ORA·GSEA)이 같기 때문입니다.
- 단일세포 경로 활성 —
gp.ssgsea()로 scanpy의 클러스터별 유사벌크(pseudobulk) 발현에 경로 점수를 매기면, 세포 유형마다 어떤 경로가 켜졌는지 히트맵으로 볼 수 있습니다. - 결과 저장·보고 —
enr.results.to_csv("ora.csv")·pre.res2d.to_csv("gsea.csv")로 표를 저장하고, 닷플롯·enrichment plot을 논문 그림으로 씁니다.outdir='결과폴더'를 주면 표와 그림이 자동으로 저장됩니다.
ORA (Enrichr) vs GSEA (prerank) — 무엇을 언제 쓸까
| 항목 | ORA — gp.enrichr() | GSEA — gp.prerank() |
|---|---|---|
| 입력 | 유의 유전자 목록(잘라낸 DEG) | 전체 유전자 순위(자르지 않음) |
| 질문 | "이 경로가 배경보다 과대표현됐나" | "이 경로가 순위 위/아래로 쏠렸나" |
| 통계 | Fisher 정확검정(초기하) | enrichment score + 순열검정 |
| 컷 필요 | 예 (padj 문턱으로 목록 정의) | 아니오 (문턱 없이 전체 사용) |
| 출력 | Overlap·조정 p·Genes | ES·NES·FDR q·leading edge |
| 강점 | 빠르고 직관적·해석 쉬움 | 약하지만 일관된 신호 포착 |
| 약점 | 컷에 민감·문턱 밑 정보 버림 | 순위 지표 선택에 민감 |
결론부터 말하면, 둘은 경쟁이 아니라 상보 관계입니다. 강한 DEG가 뚜렷하면 ORA가 빠르고 명료하고, 변화가 작지만 한 방향으로 모이는 미묘한 신호(예: 대사·리보솜 경로 전반의 완만한 하향)는 GSEA라야 잡힙니다. 실무에선 둘 다 돌려, ORA로 굵직한 경로를 확인하고 GSEA로 놓친 일관 신호를 보완하는 식이 흔합니다. gseapy는 이 둘을 한 라이브러리로 제공하니, 파이썬 파이프라인 안에서 DEG→해석까지 끊김 없이 이어집니다.
• (입력 만들기) pydeseq2로 RNA-seq 차등발현 — 이 글에 넣을 DEG 목록·순위를 뽑는 앞 단계
• (R 짝) clusterProfiler로 GO·KEGG·GSEA 농축분석 — 같은 분석을 R로, 교차검증용
• (통계 기초) p-value와 FDR, 다중검정보정 — 조정 p·FDR q가 왜 필요한지
• (결과 시각화) matplotlib·seaborn 생물 데이터 시각화 — 닷플롯·플롯을 더 다듬기
References
- Subramanian, A., Tamayo, P., Mootha, V. K., et al. (2005). Gene set enrichment analysis: a knowledge-based approach for interpreting genome-wide expression profiles. PNAS, 102(43), 15545–15550. (GSEA 원논문)
- Fang, Z., Liu, X., & Peltz, G. (2023). GSEApy: a comprehensive package for performing gene set enrichment analysis in Python. Bioinformatics, 39(1), btac757. (gseapy 원논문)
- Chen, E. Y., Tan, C. M., Kou, Y., et al. (2013). Enrichr: interactive and collaborative HTML5 gene list enrichment analysis tool. BMC Bioinformatics, 14, 128. (Enrichr 원논문)
- Kuleshov, M. V., Jones, M. R., Rouillard, A. D., et al. (2016). Enrichr: a comprehensive gene set enrichment analysis web server 2016 update. Nucleic Acids Research, 44(W1), W90–W97. (Enrichr 웹서버)
- GSEApy documentation. (2024). A protocol to prepare files for GSEA · Enrichr · Prerank. gseapy.readthedocs.io
Pipette & Pipeline · A bio portfolio journal
'Code Bench > Python for Bio' 카테고리의 다른 글
| pydeseq2로 RNA-seq 차등발현 — R 없이 파이썬만으로 DESeq2 (카운트→볼케이노) (1) | 2026.07.07 |
|---|---|
| numpy·scipy로 생물 데이터 수치·통계 — 배열 연산·가설검정 (0) | 2026.07.01 |
| scikit-learn으로 생물 데이터 머신러닝 — 분류·교차검증·ROC (0) | 2026.06.29 |
| matplotlib·seaborn으로 생물 데이터 시각화 — 발현 데이터 플롯 실전 (0) | 2026.06.25 |
| scanpy로 단일세포 RNA-seq 분석하기 — QC부터 UMAP·클러스터까지 (Python for Bio) (0) | 2026.06.23 |



























