부록 E15: single-cell 분석 프로그래밍
이 장에서 배울 것
이번 장에서는 단일세포 분석 프로그래밍(single-cell analysis programming)을 배웁니다. 단일세포 분석은 여러 세포를 한꺼번에 평균내지 않고, 세포 하나하나의 유전자 발현을 따로 측정하고 분석하는 방법입니다.
핵심 용어를 먼저 정리하겠습니다.
- 단일세포 RNA-seq(scRNA-seq): 세포 하나하나의 RNA 발현량을 측정하는 실험입니다. 앞으로는 필요한 곳에서 scRNA-seq이라고도 부르겠습니다.
- 세포 바코드(cell barcode): read가 어느 세포에서 왔는지 알려주는 짧은 이름표입니다.
- UMI(unique molecular identifier): 같은 RNA 분자에서 나온 read를 구분하기 위한 짧은 이름표입니다. 앞으로는 UMI라고 부르겠습니다.
- count matrix: 행은 세포, 열은 유전자, 값은 발현 count인 숫자 표입니다.
- 품질관리(QC): 품질이 낮은 세포나 유전자를 걸러내는 단계입니다.
- 정규화(normalization): 세포마다 read 수가 다른 문제를 보정하는 단계입니다.
- 고변동 유전자(highly variable genes): 세포들 사이에서 차이를 잘 보여주는 유전자들입니다.
- 차원축소(dimensionality reduction): 수천 개 유전자 정보를 2~50개 정도의 축으로 줄여 보는 방법입니다.
- 클러스터링(clustering): 비슷한 세포끼리 묶는 작업입니다.
- 세포 유형 주석(cell type annotation): 각 클러스터가 어떤 세포 유형인지 이름을 붙이는 작업입니다.
가장 쉬운 비유: 교실 전체 평균 대신 학생별 성적표 보기
일반 RNA-seq은 반 전체 평균 성적을 보는 것과 비슷합니다. 평균이 80점이면 반 전체가 어느 정도인지 알 수 있지만, 어떤 학생이 수학을 잘하고 어떤 학생이 영어를 잘하는지는 보이지 않습니다.
단일세포 분석은 학생별 성적표를 보는 것과 비슷합니다. 세포 하나하나가 “학생”이고, 유전자 발현량이 “과목 점수”입니다. 그래서 세포마다 어떤 특징이 있는지 볼 수 있습니다.
count matrix의 모양
단일세포 분석의 기본 데이터는 큰 숫자 표입니다.
cell GeneA GeneB GeneC
cell_1 0 5 1
cell_2 3 0 8
cell_3 1 7 0
여기서 한 행은 세포 하나입니다. 한 열은 유전자 하나입니다. 값은 그 세포에서 해당 유전자가 얼마나 관찰되었는지를 나타냅니다.
세포 바코드와 UMI
단일세포 실험에서는 많은 세포의 RNA가 한꺼번에 처리됩니다. 그러면 read가 어느 세포에서 왔는지 구분해야 합니다. 이때 세포 바코드가 붙습니다.
UMI는 같은 RNA 분자가 PCR 과정에서 여러 번 복사되어 read가 많아 보이는 문제를 줄이는 데 도움을 줍니다. 쉽게 말해 세포 바코드는 “어느 세포의 것인가?”, UMI는 “어느 원래 분자의 것인가?”를 알려주는 이름표입니다.
QC: 먼저 나쁜 세포를 걸러야 합니다
단일세포 데이터에는 품질이 낮은 세포가 섞일 수 있습니다. 예를 들어 죽어 가는 세포, RNA가 너무 적게 잡힌 세포, 두 세포가 한 방울에 같이 들어간 경우가 있을 수 있습니다.
QC에서 자주 보는 값은 다음과 같습니다.
세포별 총 count 수
세포별 검출 유전자 수
미토콘드리아 유전자 비율
미토콘드리아 유전자 비율이 너무 높으면 세포가 손상되었을 가능성을 의심할 수 있습니다. 물론 기준값은 데이터와 실험 조건에 따라 달라집니다.
Python에서 AnnData로 다루기
파이썬에서는 Scanpy라는 라이브러리를 많이 씁니다. Scanpy는 단일세포 데이터를 AnnData라는 형태로 다룹니다.
import scanpy as sc
adata = sc.read_h5ad("cells.h5ad")
print(adata.shape)
adata.shape이 (1000, 20000)이라면 세포 1000개와 유전자 20000개가 있다는 뜻입니다.
기본 분석 흐름
단일세포 분석은 보통 다음 흐름으로 진행됩니다.
count matrix 읽기
→ QC
→ 정규화
→ 로그 변환
→ 고변동 유전자 선택
→ PCA
→ 이웃 그래프 만들기
→ 클러스터링
→ UMAP 시각화
→ 세포 유형 주석
이 흐름은 처음 보면 길지만, 큰 뜻은 단순합니다. 먼저 나쁜 데이터를 줄이고, 세포 간 차이를 잘 보여주는 유전자를 고른 다음, 비슷한 세포끼리 묶습니다.
작은 코드 예시
실제 코드는 데이터마다 달라지지만, 흐름은 다음처럼 생겼습니다.
import scanpy as sc
adata = sc.read_h5ad("cells.h5ad")
sc.pp.filter_cells(adata, min_genes=200)
sc.pp.normalize_total(adata)
sc.pp.log1p(adata)
sc.tl.pca(adata)
sc.pp.neighbors(adata)
sc.tl.leiden(adata)
sc.tl.umap(adata)
여기서 pp는 전처리(preprocessing), tl은 분석 도구(tool)를 뜻합니다. 처음에는 함수 이름을 다 외우기보다, 각 줄이 파이프라인의 어느 단계인지 이해하는 것이 중요합니다.
클러스터를 해석할 때 조심할 점
클러스터가 나뉘었다고 해서 자동으로 생물학적 세포 유형이 정해지는 것은 아닙니다. 특정 마커 유전자(marker gene, 어떤 세포 유형을 알려주는 단서 유전자)를 보고, 기존 생물학 지식과 비교해 해석해야 합니다.
예를 들어 어떤 클러스터에서 T 세포 마커가 높게 나오면 그 클러스터를 T 세포로 추정할 수 있습니다. 하지만 자동 주석 결과를 무조건 믿으면 안 됩니다. 실험 조건, 종, 조직, 데이터 품질에 따라 해석이 달라질 수 있습니다.
실전 보강: 0이 많다는 뜻과 dropout
single-cell count matrix에는 0이 매우 많습니다. 어떤 세포에서 어떤 유전자의 count가 0이라고 해서 그 유전자가 생물학적으로 완전히 꺼져 있다고 단정하면 안 됩니다. 실제로는 RNA 분자가 있었지만 잡히지 않았을 수 있습니다. 이런 현상을 dropout이라고 부릅니다.
cell GeneA GeneB GeneC
cell_1 0 5 1
cell_2 3 0 8
cell_3 0 0 0
cell_3처럼 전체 count가 지나치게 낮은 세포는 품질이 낮은 세포일 수 있습니다. 반면 특정 유전자 하나만 0인 것은 dropout일 수 있습니다. 그래서 single-cell 분석은 한 유전자 하나만 보지 않고, 여러 marker gene과 전체 패턴을 함께 봅니다.
실전 보강: doublet, batch effect, UMAP 해석
단일세포 실험에서는 두 세포가 한 방울에 같이 들어가 하나의 세포처럼 기록될 수 있습니다. 이것을 doublet이라고 합니다. doublet은 두 세포 유형의 marker가 섞여 이상한 세포처럼 보일 수 있습니다.
Batch effect도 중요합니다. 첫째 날 처리한 샘플과 둘째 날 처리한 샘플이 기술적 차이 때문에 서로 다른 클러스터로 보일 수 있습니다. 이때 클러스터가 생물학적 세포 유형 차이인지, 실험 배치 차이인지 구분해야 합니다.
UMAP은 복잡한 유전자 발현 패턴을 2차원 그림으로 압축한 것입니다. 가까운 점들이 비슷한 세포일 가능성은 있지만, UMAP 위의 거리와 방향을 물리적 거리처럼 과해석하면 안 됩니다.
초보자가 자주 하는 오해
- 오해 1: 클러스터 하나는 반드시 세포 유형 하나다. 클러스터는 계산으로 묶은 결과이며, marker gene과 생물학 지식으로 해석해야 합니다.
- 오해 2: UMAP에서 멀면 반드시 완전히 다른 세포다. UMAP은 시각화 도구이지 절대 거리 지도는 아닙니다.
- 오해 3: 0 count는 항상 발현 없음이다. single-cell에서는 dropout 때문에 0이 많이 생깁니다.
- 오해 4: QC 기준은 모든 데이터에 똑같다. 조직, 플랫폼, 실험 조건에 따라 기준을 조정해야 합니다.
이전 개념과 다음 개념의 연결
single-cell 분석은 RNA-seq의 count matrix 사고를 세포 단위로 확장한 것입니다. 세포와 유전자가 많아지면 E16 알고리즘 복잡도와 E22 HPC가 중요해지고, 분석 환경과 결과 재현은 E20, E21, E24와 직접 연결됩니다.
생물정보학에서 왜 중요한가
단일세포 분석은 세포 유형, 발생 과정, 암 미세환경, 면역세포 상태를 연구하는 데 매우 강력합니다. 프로그래밍 관점에서는 큰 희소 행렬(sparse matrix, 대부분 값이 0인 행렬)을 다루고, 차원축소와 클러스터링을 연결하는 대표적인 분석입니다.
어려운 개념 보강: 단일세포 QC 지표와 정규화 공식 읽기
단일세포 분석에서 어려운 부분은 알고리즘 이름보다 QC 지표의 의미입니다. 세포 하나하나가 분석 단위이므로, 품질이 낮은 세포를 그대로 두면 클러스터가 생물학적 차이가 아니라 기술적 잡음으로 나뉠 수 있습니다.
자주 보는 QC 지표는 세 가지입니다.
total_counts: 한 세포에서 관찰된 전체 UMI 또는 read count
n_genes_by_counts: 한 세포에서 검출된 유전자 수
mito_fraction: 미토콘드리아 유전자 count 비율
미토콘드리아 비율은 보통 다음처럼 계산합니다.
mito_fraction = 미토콘드리아 유전자 count 합 / 전체 count 합
예를 들어 어떤 세포의 전체 count가 10,000이고, 그중 미토콘드리아 유전자 count가 1,500이면 다음과 같습니다.
mito_fraction = 1,500 / 10,000 = 0.15 = 15%
미토콘드리아 비율이 지나치게 높으면 세포가 손상되었거나 스트레스를 받았을 가능성을 의심할 수 있습니다. 다만 모든 조직에 같은 기준을 기계적으로 적용하면 안 됩니다. 조직과 실험 방식에 따라 정상 범위가 달라질 수 있습니다.
정규화는 세포마다 전체 count가 다른 문제를 줄이기 위해 사용합니다. 한 가지 단순한 직관은 “각 세포의 총량을 비슷한 규모로 맞춘 뒤 비교한다”입니다.
정규화 값 = 특정 유전자 count / 해당 세포 전체 count × 10,000
예를 들어 한 세포에서 GeneA count가 50이고 전체 count가 10,000이면 정규화 값은 50입니다. 다른 세포에서 GeneA count가 100이고 전체 count가 20,000이어도 정규화 값은 50입니다. raw count는 다르지만 전체 규모를 고려하면 비슷한 비율이라는 뜻입니다.
그다음 log1p 변환을 자주 씁니다.
log1p(x) = log(1 + x)
1을 더하는 이유는 count가 0인 값도 계산할 수 있게 하기 위해서입니다. 로그 변환은 매우 큰 값의 영향을 줄이고, 작은 값들의 차이를 보기 쉽게 만듭니다.
주의할 점은 정규화와 차원축소가 생물학적 진실을 자동으로 만들어 주지는 않는다는 것입니다. UMAP에서 가까운 점은 비슷한 발현 패턴을 가질 가능성이 있지만, 거리 자체를 실제 생물학적 시간이나 물리적 거리처럼 해석하면 위험합니다.
미니 실습 블록: single-cell count matrix와 cell metadata 확인하기
이 실습은 single-cell count matrix와 cell metadata 확인하기를 직접 손으로 확인하는 연습입니다. 왜 필요한가 하면, single-cell 분석은 샘플보다 세포 단위 metadata가 중요하고, 품질 낮은 세포가 클러스터 해석을 왜곡할 수 있기 때문입니다.
import pandas as pd
cell_meta = pd.DataFrame({
"cell_id": ["C1", "C2", "C3"],
"n_genes": [1200, 300, 2500],
"pct_mito": [5.2, 30.1, 7.0]
})
filtered = cell_meta[(cell_meta["n_genes"] >= 500) & (cell_meta["pct_mito"] < 20)]
print(filtered)
각 코드 요소의 의미를 풀어보면 다음과 같습니다. n_genes는 한 세포에서 검출된 유전자 수, pct_mito는 미토콘드리아 유전자 비율입니다. 극단적으로 낮은 n_genes나 높은 pct_mito는 품질 문제 신호일 수 있습니다.
생물정보학/계산생물학에서 쓰이는 장면은 분명합니다. single-cell RNA-seq에서 QC 후 normalization, PCA, clustering, marker gene 해석으로 넘어가기 전 단계입니다.
흔한 오해 또는 주의점도 있습니다. QC 기준은 데이터와 조직에 따라 달라질 수 있으므로 숫자를 기계적으로 복사하면 안 됩니다.
핵심 정리
단일세포 분석은 세포 하나하나의 유전자 발현을 표로 만들고, 품질관리, 정규화, 차원축소, 클러스터링, 세포 유형 주석을 거쳐 해석합니다. 핵심은 세포를 하나의 벡터로 보고, 비슷한 세포끼리 묶어 생물학적 의미를 찾는 것입니다.
문제 풀이
single-cell 분석 프로그래밍
주관식 답안은 Gemini API로 채점합니다. API 키는 이 브라우저에만 저장됩니다.
-
1. [객관식] 객관식
단일세포 분석의 핵심 관점으로 적절한 것은?
-
2. [객관식] 객관식
세포 바코드(cell barcode)의 역할은?
-
3. [객관식] 객관식
UMI의 역할로 적절한 것은?
-
4. [객관식] 객관식
단일세포 count matrix의 일반적 모양으로 적절한 것은?
-
5. [객관식] 객관식
QC에서 자주 보는 값으로 적절한 것은?
-
6. [객관식] 객관식
미토콘드리아 유전자 비율이 너무 높을 때 의심할 수 있는 것은?
-
7. [객관식] 객관식
adata.shape이(1000, 20000)일 때 뜻으로 적절한 것은? -
8. [객관식] 객관식
고변동 유전자 선택의 목적은?
-
9. [객관식] 객관식
PCA와 UMAP이 주로 돕는 일은?
-
10. [객관식] 객관식
클러스터링의 설명으로 적절한 것은?
-
11. [객관식] 객관식
세포 유형 주석에서 필요한 태도로 적절한 것은?
-
12. [객관식] 객관식
Scanpy에서
sc.pp.normalize_total(adata)의 역할에 가까운 것은? -
13. [객관식] 객관식
sc.tl.pca(adata)가 하는 일에 가까운 것은? -
14. [객관식] 객관식
단일세포 데이터가 희소 행렬인 경우가 많은 이유는?
-
15. [객관식] 객관식
단일세포 분석에서 정규화 후 로그 변환을 하는 이유로 적절한 것은?
-
16. [객관식] 객관식
단일세포 분석 흐름으로 가장 적절한 것은?
-
17. [객관식] 객관식
마커 유전자(marker gene)의 설명으로 적절한 것은?
-
18. [객관식] 객관식
자동 세포 유형 주석 결과를 무조건 믿으면 안 되는 이유는?
-
19. [객관식] 객관식
sc.pp.filter_cells(adata, min_genes=200)에 가까운 의미는? -
20. [객관식] 객관식
단일세포 분석이 평균 RNA-seq보다 유리한 경우는?
-
21. [객관식] 객관식
adata.shape = (3000, 18000)일 때 가장 적절한 해석은? -
22. [객관식] 객관식
총 count가 매우 낮고 검출 유전자 수가 거의 없는 세포의 1차 판단으로 적절한 것은?
-
23. [객관식] 객관식
한 세포가 T cell marker와 B cell marker를 동시에 강하게 보이고 총 count도 비정상적으로 높다면 의심할 수 있는 것은?
-
24. [객관식] 객관식
UMAP 그림에서 두 클러스터가 멀리 떨어져 있을 때 올바른 태도는?
-
25. [객관식] 객관식
single-cell count matrix에서 0이 많은 이유로 가장 적절한 것은?
-
26. [객관식] 객관식
미토콘드리아 유전자 비율이 지나치게 높은 세포에 대한 설명으로 적절한 것은?
-
27. [객관식] 객관식
다음 코드의 의미로 가장 적절한 것은?
-
28. [객관식] 객관식
batch effect가 single-cell 분석에서 위험한 이유는?
-
29. [객관식] 객관식
클러스터 2가
MS4A1,CD79A같은 marker를 높게 보인다면 올바른 해석 태도는? -
30. [객관식] 객관식
세포 5000개와 유전자 20000개 행렬의 전체 칸 수는?
-
31. [실전] 객관식
single-cell 분석에서
pct_mito가 매우 높은 세포를 조심하는 이유는? -
32. [실전] 객관식
single-cell 분석 순서로 자연스러운 것은?
-
주관식 33. [응용] 주관식 · Gemini 채점
단일세포 분석의 기본 흐름을 설명하라.
-
주관식 34. [응용] 주관식 · Gemini 채점
세포 바코드와 UMI의 차이를 설명하라.
-
주관식 35. [응용] 주관식 · Gemini 채점
단일세포 QC에서 미토콘드리아 유전자 비율을 보는 이유를 설명하라.
-
주관식 36. [응용] 주관식 · Gemini 채점
adata.shape == (1000, 20000)의 의미를 설명하라. -
주관식 37. [응용] 주관식 · Gemini 채점
클러스터링 결과에 세포 유형 이름을 붙일 때 왜 마커 유전자가 필요한지 설명하라.
-
주관식 38. [응용] 주관식 · Gemini 채점
단일세포 분석에서 차원축소가 필요한 이유를 설명하라.
-
주관식 39. [응용] 주관식 · Gemini 채점
adata.shape = (5000, 20000)의 의미와 전체 행렬 칸 수를 계산하라. -
주관식 40. [응용] 주관식 · Gemini 채점
UMAP 클러스터를 보고 세포 유형을 붙일 때 주의할 점을 설명하라.
-
주관식 41. [실습] 주관식 · Gemini 채점
n_genes >= 500이고pct_mito < 20인 세포만 고르는 pandas 코드를 작성하라. -
주관식 42. [실습] 주관식 · Gemini 채점
single-cell count matrix에서 행과 열이 각각 무엇을 뜻할 수 있는지 설명하라.