본문 바로가기
Bioinformatics

single cell RNA-seq scExtract (2025) 따라하기

by 코딩하는 미토콘드리아 Bioinformatics Lab 2025. 10. 11.
728x90

🧠 논문 배경 요약 — scExtract (2025)

  • 이 논문은 단일세포 RNA-seq 데이터 처리 → 클러스터링 → 주석(annotation) → 여러 데이터셋 통합까지의 전 과정을
    대형 언어 모델(Large Language Model, LLM) 기반으로 자동화한 프레임워크인 scExtract을 제시합니다. BioMed Central
  • 입력으로는 raw expression matrix + 논문 관련 정보(메소드, 유전자 정보 등)만 필요하며,
    내부적으로 LLM이 논문에서 기술된 분석 방법론을 해독해 적절한 파이프라인을 설계하고 수행하는 방식입니다. BioMed Central
  • 논문에서는 scExtract가 기존 레퍼런스 전이 방식(reference transfer) 보다 더 우수한 주석 성능을 보였고,
    복수 데이터셋 통합 시에도 자동화 + 문헌 기반 prior 정보를 활용한 통합에서 강점을 보였습니다. BioMed Central

🔧 연습용 코드 예시 — scExtract 핵심 흐름 재현 (단순화 버전)

아래 코드는 scExtract 전체를 구현한 것은 아니고,
논문에서 제시한 raw count matrix → 클러스터링 → 자동 주석 후보 제시의 핵심 흐름을 단순화해서 따라 해보는 예시입니다.
(실제로 LLM API 호출 부분은 구조만 제시하고, 더미 또는 간단 로직으로 대체합니다.)

1) 환경 및 의존성 설치 (터미널 명령)

# (선택) conda 환경 생성
conda create -n scextract python=3.10 -y
conda activate scextract

pip install scanpy anndata openai matplotlib
  • 여기서는 scanpy를 사용해 단일세포 분석 기본 흐름을 처리
  • openai (또는 유사 LLM API) 라이브러리는 논문 기반 입력 해독용 가정

2) 입력 데이터 불러오기 및 전처리 (Python)

import scanpy as sc
import anndata
import pandas as pd

# 예시: raw count matrix (cells × genes)
adata = sc.read_h5ad("example_counts.h5ad")  # 또는 .loom, .mtx 등 포맷

# 기본 전처리 (필터링, 정규화, 로그 변환)
sc.pp.filter_cells(adata, min_genes=200)
sc.pp.filter_genes(adata, min_cells=3)

sc.pp.normalize_total(adata, target_sum=1e4)
sc.pp.log1p(adata)

# 고변이 유전자 선택
sc.pp.highly_variable_genes(adata, n_top_genes=2000, subset=True)

# 스케일링 & PCA
sc.pp.scale(adata, max_value=10)
sc.tl.pca(adata, svd_solver='arpack')

3) 클러스터링 & UMAP 시각화

# 인접 그래프 + 클러스터링
sc.pp.neighbors(adata, n_neighbors=10, n_pcs=40)
sc.tl.umap(adata)
sc.tl.leiden(adata, resolution=0.5)

# 클러스터 할당 결과 시각화
sc.pl.umap(adata, color=["leiden"], save="umap_clusters.png")

4) 자동 주석 후보 생성 (LLM 기반 논문 해독 모사)

# 이 부분은 실제 LLM API 호출로 구현해야 하지만,  
# 여기선 데모용으로 간단 룰 기반 주석 제안을 합니다.

def dummy_annotate(cluster_gene_list: list[str]) -> str:
    """
    클러스터별 특징 유전자 목록을 받고, 간단 룰로 주석을 제시하는 더미 함수.
    실제론 논문 + LLM 기반으로 유전자 기능 정보를 참조해서 주석을 생성해야 함.
    """
    # 임의 룰: 만약 cluster에 'CD3D' 유전자 포함 시 T cell 가능성
    if "CD3D" in cluster_gene_list:
        return "T cell (추정)"
    if "MS4A1" in cluster_gene_list:
        return "B cell (추정)"
    return "Unknown cell type"

# 각 클러스터별 상위 marker 유전자 추출 + 주석
import numpy as np

cluster_annotations = {}
for cl in adata.obs["leiden"].cat.categories:
    # 각 클러스터 내 평균 발현 상위 10개 유전자
    subset = adata[adata.obs["leiden"] == cl]
    mean_expr = subset.X.mean(axis=0).A1 if hasattr(subset.X, "A1") else subset.X.mean(axis=0)
    genes = list(adata.var_names[np.argsort(-mean_expr)[:10]])
    cluster_annotations[cl] = dummy_annotate(genes)

print("Cluster annotations (예시):")
for cl, ann in cluster_annotations.items():
    print(f"클러스터 {cl} → {ann}")

이렇게 하면 leiden 클러스터별로 예비 주석을 콘솔에 출력할 수 있습니다.


5) 통합 (여러 데이터셋) 흐름 예시 (단순화)

# 예: 두 개 이상의 AnnData 객체 통합하기
adata1 = sc.read_h5ad("dataset1.h5ad")
adata2 = sc.read_h5ad("dataset2.h5ad")

# 전처리 일치시키고, scanpy의 BBKNN 또는 Harmony 등을 이용한 통합
import scanpy.external as sce

# 먼저 normalization, var selection 등 동일 처리
for ad in [adata1, adata2]:
    sc.pp.normalize_total(ad, target_sum=1e4)
    sc.pp.log1p(ad)
    sc.pp.highly_variable_genes(ad, n_top_genes=2000, subset=True)
    sc.pp.scale(ad, max_value=10)
    sc.tl.pca(ad, svd_solver='arpack')

# 통합: 간단히 concatenate 후 batch-correction
adata_concat = anndata.AnnData.concatenate(adata1, adata2, batch_key="batch")

# 예: scanpy.external.bbknn 으로 배치 효과 보정
sce.pp.bbknn(adata_concat, batch_key="batch")

# 이후 neighbors, clustering, UMAP
sc.pp.neighbors(adata_concat, n_neighbors=10, n_pcs=40)
sc.tl.umap(adata_concat)
sc.tl.leiden(adata_concat, resolution=0.5)

# 클러스터 기반 자동 주석 (위 dummy 함수 재사용)
for cl in adata_concat.obs["leiden"].cat.categories:
    subset = adata_concat[adata_concat.obs["leiden"] == cl]
    mean_expr = subset.X.mean(axis=0).A1 if hasattr(subset.X, "A1") else subset.X.mean(axis=0)
    genes = list(adata_concat.var_names[np.argsort(-mean_expr)[:10]])
    print(f"클러스터 {cl} → {dummy_annotate(genes)}")