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 농축분석 워크플로 — DEG 목록은 Enrichr(ORA)로, 순위 리스트는 prerank(GSEA)로 갈라져 농축표와 플롯으로 이어진다.

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. 샘플마다 경로 활성 점수를 매겨, 히트맵이나 후속 분석에 넘깁니다.
그림 2. ORA와 GSEA — 같은 DEG 결과에서 출발하지만 입력·질문·통계·출력이 다르다. 컷이 필요한 목록 기반이 ORA, 컷 없는 순위 기반이 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()를 씁니다.

그림 3. GSEA enrichment plot 3단 — running ES 곡선의 정점이 ES, 막대가 순위표 어디 몰렸는지가 NES 부호, 정점까지 기여한 유전자가 leading edge다.

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.resultsAdjusted P-value를, GSEA(prerank)는 pre.res2dFDR 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 결과로 바로 잇기pydeseq2results_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·GenesES·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

  1. 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 원논문)
  2. Fang, Z., Liu, X., & Peltz, G. (2023). GSEApy: a comprehensive package for performing gene set enrichment analysis in Python. Bioinformatics, 39(1), btac757. (gseapy 원논문)
  3. 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 원논문)
  4. 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 웹서버)
  5. GSEApy documentation. (2024). A protocol to prepare files for GSEA · Enrichr · Prerank. gseapy.readthedocs.io

Pipette & Pipeline · A bio portfolio journal

이 글을 쓴 사람 Yumingming

생명융합공학과 박사과정.
Microbiome · Cosmetics · RNA Therapeutics · Bioinformatics를 공부하며,
실험(Wet Lab)과 데이터(Dry Lab)를 잇는 글을 논문(article) 기반으로 씁니다.

About · 더 알아보기 →

⚕️ 이 글은 학습·정보 제공 목적이며, 의학적 진단·치료·조언을 대체하지 않습니다. 건강·질병·치료에 관한 결정은 반드시 의사 등 전문가와 상의하세요. 자세한 내용은 면책조항을 참고해 주세요.