Bioinformatics

프로테오믹스 분석 플랫폼을 직접 만들어봤다

BioAI Market — 웹 기반 프로테오믹스 분석 플랫폼의 기술적 구현기. QC부터 DE, Pathway 분석까지 파이프라인 설계, ANOVA 벡터화로 215초→5초 최적화, limma 통합, 멀티그룹 UI 구현 경험을 공유한다.

·9 min read
#프로테오믹스#BioAI#limma#ANOVA#Pathway#GO#KEGG#생물정보학

A scientist analyzing data on a computer screen in a laboratory

BioAI Market이란

BioAI Market은 웹 브라우저에서 프로테오믹스 데이터를 업로드하고, QC → DE → Pathway 분석을 원클릭으로 실행할 수 있는 플랫폼이다. R과 Python 코딩 없이도 분석이 가능하도록 만드는 게 목표였다.

기존에 프로테오믹스 분석을 하려면 R에서 limma 스크립트를 짜거나, Perseus 같은 데스크톱 소프트웨어를 쓰거나, Python으로 직접 파이프라인을 구축해야 했다. 연구자들이 이 과정에서 겪는 고통을 줄이고 싶었다.

분석 파이프라인 설계

전체 파이프라인은 3단계로 구성된다:

[전처리] → [QC] → [DE] → [Pathway]

전처리: Filtering → Imputation → Log2 Transform → Median Normalization
QC:     PCA, CV(Coefficient of Variation), Sample Correlation
DE:     limma / Welch's t-test / ANOVA + Tukey HSD
Pathway: GO (Biological Process, Molecular Function, Cellular Component) + KEGG

전처리 — 순서가 중요하다

프로테오믹스 raw 데이터는 결측치(missing values)가 많고, intensity 값의 분포가 skewed되어 있다. 전처리 순서를 잘못 잡으면 결과가 완전히 달라진다.

1. Filtering    — 결측치가 70%+ 이상인 단백질 제거
2. Imputation   — 나머지 결측치를 minimum value의 1/2로 대체
3. Log2 Transform — intensity를 log2 스케일로 변환
4. Median Normalization — 샘플 간 중앙값을 맞춤

처음에는 Log2 → Imputation 순서로 했다가, log2(0) = -Infinity 문제에 부딪혔다. Imputation을 먼저 하고 Log2를 해야 한다.

DE 방법 자동 선택 — 통계 검정으로 결정

사용자가 통계를 몰라도 적절한 DE 방법이 선택되도록 자동 추천 시스템을 만들었다.

from scipy import stats

def recommend_de_method(data, groups):
    """데이터 특성에 따라 DE 방법을 자동 추천"""
    n_groups = len(set(groups))

    if n_groups == 2:
        # 정규성 검정 (Shapiro-Wilk)
        _, p_normal = stats.shapiro(data.iloc[:, 0])
        is_normal = p_normal > 0.05

        # 등분산성 검정 (Levene)
        group_data = [data[groups == g].values.flatten() for g in set(groups)]
        _, p_levene = stats.levene(*group_data)
        is_equal_var = p_levene > 0.05

        if is_normal and is_equal_var:
            return "limma"  # Gold standard
        elif is_normal:
            return "welch"  # 등분산 가정 불필요
        else:
            return "limma"  # limma는 비정규에도 robust
    else:
        return "anova"  # 3그룹 이상

실제로는 limma를 거의 항상 추천하게 된다. Empirical Bayes moderated t-test는 소규모 샘플에서 분산 추정이 안정적이라, 프로테오믹스처럼 반복 수가 적은 실험에 이상적이다.

ANOVA 벡터화 — 215초를 5초로

3그룹 이상 비교에서 ANOVA를 돌려야 하는데, 처음에는 순진하게 per-protein 루프를 돌렸다:

# ❌ Before: per-protein 루프 — 215초
from scipy.stats import f_oneway

results = []
for protein_idx in range(n_proteins):  # 5000+ proteins
    groups_data = []
    for group in unique_groups:         # 9 groups
        mask = group_labels == group
        groups_data.append(data[mask, protein_idx])

    f_stat, p_value = f_oneway(*groups_data)
    results.append({"protein": proteins[protein_idx], "f": f_stat, "p": p_value})

# 5000 proteins × 9 groups = 215초 소요

5000개 단백질 × 9그룹에서 215초가 걸렸다. Python for-loop의 한계다.

Numpy 행렬 연산으로 벡터화했다:

# ✅ After: numpy 벡터화 — 5초
import numpy as np

def vectorized_anova(data, group_labels):
    """
    data: (n_samples, n_proteins) array
    group_labels: (n_samples,) array
    """
    unique_groups = np.unique(group_labels)
    n_groups = len(unique_groups)
    n_total = data.shape[0]
    grand_mean = data.mean(axis=0)  # (n_proteins,)

    # SSB (Sum of Squares Between)
    ssb = np.zeros(data.shape[1])
    # SSW (Sum of Squares Within)
    ssw = np.zeros(data.shape[1])

    for group in unique_groups:
        mask = group_labels == group
        n_g = mask.sum()
        group_mean = data[mask].mean(axis=0)
        ssb += n_g * (group_mean - grand_mean) ** 2
        ssw += ((data[mask] - group_mean) ** 2).sum(axis=0)

    df_between = n_groups - 1
    df_within = n_total - n_groups

    msb = ssb / df_between
    msw = ssw / df_within
    f_stats = msb / msw

    from scipy.stats import f as f_dist
    p_values = 1 - f_dist.cdf(f_stats, df_between, df_within)

    return f_stats, p_values

# 5000 proteins × 9 groups = 5초 소요 (43배 개선)

215초 → 5초. 루프 안의 그룹별 연산은 남아있지만(9번), 핵심인 per-protein 루프가 사라졌기 때문에 극적으로 빨라졌다.

Tukey HSD — significant만 처리

ANOVA에서 유의미한 단백질이 나오면 어느 그룹 간 차이인지 Tukey HSD로 다중 비교를 한다. 하지만 5000개 전부에 대해 Tukey를 돌리면 또 느려지니, BH(Benjamini-Hochberg) correction 후 significant한 단백질만 처리했다:

from statsmodels.stats.multicomp import pairwise_tukeyhsd
from statsmodels.stats.multitest import multipletests

# BH correction
_, adj_pvalues, _, _ = multipletests(p_values, method='fdr_bh')

# Significant 단백질만 Tukey HSD
significant_mask = adj_pvalues < 0.05
significant_indices = np.where(significant_mask)[0]

tukey_results = {}
for idx in significant_indices:
    result = pairwise_tukeyhsd(data[:, idx], group_labels, alpha=0.05)
    tukey_results[proteins[idx]] = result

멀티그룹 UI — 드래그앤드롭의 고통

기술적으로 가장 까다로웠던 건 UI였다. 사용자가 N개 그룹을 동적으로 추가/삭제하고, 샘플을 드래그앤드롭으로 그룹에 배정하는 인터페이스를 만들어야 했다.

처음에는 그룹 이름으로 매칭을 시도했다:

// ❌ 이름 매칭 — 실패
// "Control_1", "Control_2" → "Control" 그룹
// "Treatment_A_1", "Treatment_A_2" → "Treatment_A" 그룹
// 근데 "WT_young_rep1" 같은 이름은? 규칙이 없다

샘플 이름의 네이밍 규칙이 연구실마다 다 달라서 자동 매칭이 불가능했다. 결국 위치 기반 매핑으로 전환했다. 사용자가 CSV 컬럼 순서대로 그룹을 지정하는 방식:

// ✅ 위치 기반 매핑
// 컬럼 순서: [S1, S2, S3, S4, S5, S6]
// 그룹 매핑: [Control, Control, Control, Treatment, Treatment, Treatment]
// → 앞 3개가 Control, 뒤 3개가 Treatment

그리고 비교 설정도 위치 기반으로:

interface Comparison {
  control: number  // 그룹 인덱스
  treatment: number  // 그룹 인덱스
}

// 그룹 0 vs 그룹 1 → {control: 0, treatment: 1}

3종 생물 지원 — Human, Mouse, Rat

Pathway 분석에서 organism을 지원해야 한다. GO/KEGG 분석에 사용하는 annotation DB가 종마다 다르기 때문이다:

ORGANISM_CONFIG = {
    "human": {
        "orgDb": "org.Hs.eg.db",
        "kegg": "hsa",
        "name": "Homo sapiens"
    },
    "mouse": {
        "orgDb": "org.Mm.eg.db",
        "kegg": "mmu",
        "name": "Mus musculus"
    },
    "rat": {
        "orgDb": "org.Rn.eg.db",
        "kegg": "rno",
        "name": "Rattus norvegicus"
    }
}

처음에는 Human만 지원했는데, "Mouse 데이터도 분석할 수 있나요?"라는 피드백을 받고 추가했다. annotation DB가 각각 수백 MB라서 Docker 이미지가 4GB를 넘긴 이유이기도 하다.

현재 상태와 남은 과제

BioAI Market은 현재 아래 기능이 동작한다:

  • ✅ CSV 업로드 및 전처리
  • ✅ QC 분석 (PCA, CV, Correlation)
  • ✅ DE 분석 (limma, Welch, ANOVA + Tukey)
  • ✅ Pathway 분석 (GO + KEGG)
  • ✅ AI 결과 해석 (Ollama)
  • ✅ 바이오마커 시맨틱 검색
  • ✅ 리포트 자동 생성

남은 과제:

  • TMT/iTRAQ 등 다양한 정량 방식 지원
  • GSEA(Gene Set Enrichment Analysis) 추가
  • 배치 분석 (여러 데이터셋 동시 처리)
  • 논문 figure 수준의 시각화

직접 만들어보면서 느낀 건, 프로테오믹스 분석이 "코드 몇 줄"이 아니라 수많은 통계적 판단과 예외 처리의 집합체라는 것이다. 그래도 만드는 과정 자체가 공부가 많이 됐다.


참고 링크:

관련 글