R과 Python, 오믹스 분석에는 언제 무엇을 쓸까요? 도구 고르기와 재현 가능한 코드 남기기

📌 이 글에서 알 수 있는 것

  • R/Bioconductor와 Python이 각각 강한 분석 단계
  • BiocManager로 릴리스 맞춰 설치하기, 두 언어로 count 표 읽기와 그림 한 장
  • reticulate·rpy2와 파일 교환(TSV·parquet·h5ad)으로 두 언어 오가기
  • renv·sessionInfo·시드·노트북 재실행으로 재현 가능한 코드 남기기

🧭 언어 싸움 대신 도구 고르기

오믹스 분석에서 “R이냐 Python이냐"는 보통 필요한 도구가 어느 언어로 만들어졌느냐로 정해집니다. 3편(정렬·변이 호출)과 12편(차등발현)에서 만드는 VCF·count 같은 표를 통계 검정과 그림으로 바꾸는 단계에서 두 언어가 쓰입니다.

어느 쪽이 “많이 쓰이는지"를 보여 주는 2021년 이후 생물정보 분야 설문은 찾지 못했습니다. 생의학 논문에 딸린 Jupyter 노트북 27,271개를 분석한 2024년 연구에서는 Python이 82.8%, R이 3.3%였지만1, Jupyter만 센 숫자라 R Markdown·Quarto로 공유된 R 코드는 빠져 있습니다. 언어 점유율로 읽으면 안 됩니다.

R과 Python 비교 요약표. 설치와 버전, 표 읽기, 데이터 객체, 그림, 환경 기록, 언어 사이 교환 파일을 두 열로 비교하고, 아래에 단계마다 한 언어를 쓰고 파일로 넘기라는 원칙이 적혀 있다.
그림 1. R과 Python의 같은 작업, 다른 도구. 도구 이름은 예시이며 특정 제품을 권하지 않습니다.

📦 R과 Bioconductor: 릴리스를 맞춰 설치

Bioconductor는 오믹스용 R 패키지 저장소입니다. R은 1년에 한 번, Bioconductor는 1년에 두 번 릴리스하고, 패키지는 같은 릴리스끼리 쓸 때 가장 잘 맞습니다2. 2026-11-06 기준 release는 4월 29일에 나온 3.23(소프트웨어 패키지 2,418개, R 4.6)이고, 3.24는 11월 25일 예정입니다34. 차등발현(DE) 분석의 DESeq2·edgeR·limma(12편)와, 유전자×시료 행렬에 유전자·시료 정보를 함께 묶는 표준 객체 SummarizedExperiment가 여기에 있습니다5.

install.packages("BiocManager")
BiocManager::install("DESeq2")
BiocManager::version()
BiocManager::valid()
  • install.packages("BiocManager"): CRAN(R 기본 저장소)에서 설치 관리자를 받습니다.
  • BiocManager::install("DESeq2"): 지금 R 버전에 맞는 Bioconductor 릴리스에서 DESeq2와 의존 패키지를 설치합니다.
  • version(): 사용 중인 Bioconductor 릴리스(예: ‘3.23’)를 보여 줍니다.
  • valid(): 오래됐거나 다른 릴리스에서 온 패키지를 찾아 줍니다2.
  • 자주 하는 실수: Bioconductor 패키지를 install.packages()로 설치하려다 “not available” 오류를 보는 것.

🐍 Python: pandas에서 AnnData까지

Python에서는 표는 pandas, 수치 계산은 numpy·scipy, 그림은 matplotlib·seaborn, 머신러닝은 scikit-learn이 기본입니다. Python의 단일세포 분석은 AnnData(세포×유전자 행렬과 주석을 묶는 객체, h5ad 파일)와 scanpy가 중심이고, R에서는 Seurat과 Bioconductor의 SingleCellExperiment가 같은 역할을 합니다678. 단일세포 분석 자체는 별도 글에서 다룰 예정입니다.

같은 count 표(첫 열이 유전자 ID인 TSV)를 두 언어로 읽어 봅니다.

counts <- read.delim("counts.tsv", row.names = 1, check.names = FALSE)
dim(counts); head(rownames(counts))
  • read.delim: 탭 구분, 첫 줄을 열 이름으로 읽는 것이 기본입니다9.
  • row.names = 1: 첫 열(유전자 ID)을 행 이름으로 씁니다.
  • check.names = FALSE: 기본값 TRUE는 1-A 같은 시료 이름을 X1.A로 바꿉니다9.
  • 자주 하는 실수: 시료 이름이 바뀐 줄 모르고 메타데이터와 맞추다 어긋나는 것.
import pandas as pd
counts = pd.read_csv("counts.tsv", sep="\t", index_col=0)
print(counts.shape, counts.index[:5].tolist())
  • sep="\t": 기본 구분자는 쉼표라 TSV에는 꼭 지정합니다10.
  • index_col=0: 첫 열을 행 라벨(index)로 씁니다.
  • 자주 하는 실수: index_col 없이 읽어 유전자 ID가 일반 열이 되고, 행 번호 0, 1, 2…가 대신 붙는 것.
  • 자주 하는 실수 2: R은 중복된 유전자 ID가 있으면 오류로 멈추지만 pandas는 그대로 읽습니다. print(counts.index.is_unique)로 확인합니다(False면 중복).

그림 한 장(시료별 총 리드 수)도 그려 봅니다.

library(ggplot2)
lib <- data.frame(sample = colnames(counts), total = colSums(counts))
ggplot(lib, aes(sample, total)) + geom_col()
ggsave("library_size.png", width = 5, height = 3, dpi = 300)
  • aes(sample, total): x축에 시료, y축에 총 리드 수를 연결하고 geom_col()로 막대를 그립니다.
  • ggsave: 마지막 그림을 크기·해상도를 정해 저장합니다11.
import matplotlib.pyplot as plt
counts.sum(axis=0).plot.bar()
plt.tight_layout(); plt.savefig("library_size_py.png", dpi=300)
  • sum(axis=0): 열(시료)별 합계입니다. axis=1이면 유전자별 합계가 됩니다.
  • 자주 하는 실수: axis를 헷갈려 시료가 아니라 유전자별 합계를 그리는 것. 막대 개수가 시료 수인지 확인합니다.

🔁 두 언어 오가기

  • reticulate: R 안에서 Python 모듈을 불러 씁니다. rpy2: Python 안에서 R을 부르고 pandas 표를 R 데이터 프레임으로 바꿉니다1213.
  • 파일 교환: 작은 표는 TSV, 큰 표는 parquet(열 단위 압축 형식), 단일세포는 h5ad. parquet은 pandas에서 pyarrow, R에서 arrow 패키지를 따로 설치해야 읽힙니다14. R에서는 anndataR가 h5ad를 직접 읽고 SingleCellExperiment로 바꿉니다8.
  • 한 단계에는 한 언어: 정규화는 R, 그림은 Python처럼 단계별로 나누고 사이를 파일로 넘기면, 각 단계를 따로 재실행·검증하기 쉽습니다.

방향도 주의합니다. SummarizedExperiment는 행이 유전자·열이 시료이고5, AnnData는 행이 관측(세포·시료)·열이 변수(유전자)입니다6. 넘길 때 전치가 필요한지 확인하세요.

🖥️ IDE와 노트북

IDE(통합 개발 환경)는 코드 편집·실행·그림 보기를 한 창에 모은 프로그램입니다.

  • RStudio·Positron: 둘 다 Posit이 만듭니다. Positron은 R·Python을 기본 지원하는 새 IDE이고, RStudio도 계속 유지·업데이트됩니다15.
  • Jupyter·JupyterLab: 코드·결과·설명을 셀 단위로 담는 노트북입니다. 코드를 실제로 실행하는 프로그램을 커널이라 하며, R 커널(IRkernel)도 있습니다.
  • Quarto·R Markdown: 코드와 글을 한 문서로 묶어 HTML·PDF로 렌더링합니다. Quarto는 R·Python·Julia를 지원하고, R Markdown도 계속 지원됩니다16.

노트북은 셀을 아무 순서로나 실행할 수 있어 위험합니다. GitHub의 노트북 1,159,568개를 분석한 2021년 연구에서, 실행 순서가 확인된 노트북의 36.36%에 순서가 뒤바뀐 셀이 있었습니다. 실행을 시도한 863,878개 중 오류 없이 끝난 것은 24.11%, 저장된 결과와 같게 나온 것은 4.03%였습니다. 대부분은 실행 오류에서 막혔으니, 낮은 재현율을 셀 순서 탓으로만 볼 수는 없습니다17.

jupyter nbconvert --to notebook --execute analysis.ipynb
quarto render analysis.qmd
  • --execute: 노트북을 위에서부터 새로 실행해 analysis.nbconvert.ipynb로 저장합니다. 오류가 나면 멈춥니다18.
  • quarto render: 문서를 처음부터 실행해 결과물을 만듭니다.
  • 자주 하는 실수: 손으로 돌린 셀 결과를 그대로 공유하는 것. 공유 전 한 번은 처음부터 돌립니다.

🔒 재현 가능한 코드 남기기

renv::init()
renv::snapshot()
renv::restore()
sessionInfo()
  • init(): 프로젝트 전용 패키지 폴더(renv/library)와 버전 목록 파일 renv.lock을 만듭니다19.
  • snapshot(): 프로젝트 코드가 불러 쓰는 패키지의 버전을 renv.lock에 기록합니다(기본값). 그 패키지들이 의존하는 패키지는 함께 기록되지만, 설치만 하고 코드에서 쓰지 않은 패키지는 빠집니다20. restore(): 다른 컴퓨터에서 renv.lock대로 다시 설치합니다.
  • sessionInfo(): R·운영체제·불러온 패키지 버전을 출력합니다. 결과 파일 옆에 저장해 두세요21.
  • 자주 하는 실수: renv가 R 자체 버전과 시스템 라이브러리까지 맞춰 준다고 믿는 것. R 버전은 기록만 합니다19.
import numpy as np
rng = np.random.default_rng(42)
  • 시드(난수 시작값)를 정하지 않으면 실행할 때마다 다른 난수가 나옵니다22. R은 set.seed(42), scikit-learn은 random_state=42로 정합니다.
  • Python 환경은 conda environment.yml로 기록합니다(6편). pip freeze > requirements.txt는 pip 패키지 목록만 남기고 Python 자체 버전이나 conda로 설치한 C 라이브러리는 남기지 않습니다23.
  • 유전자 목록을 엑셀로 열면 이름이 날짜로 바뀔 수 있습니다(5편). 코드에서 TSV로 읽고 씁니다.
  • 코드는 git으로 관리하고, 원시 데이터 대신 renv.lock·.Rprofile·renv/activate.R·renv/settings.json, environment.yml, 스크립트를 커밋합니다19. Bioconductor를 쓰면 renv::init(bioconductor = "3.23")으로 릴리스도 함께 고정합니다.

🚧 자주 하는 실수 모음

실수증상확인·해결
Bioconductor 릴리스 섞기설치 오류, 이상한 동작BiocManager::valid()2
엉뚱한 라이브러리에 설치설치했는데 불러오지 못함.libPaths() 확인, BiocVersion 중복 제거2
노트북 셀 순서 뒤섞임다시 돌리면 결과가 다름커널 재시작 후 전체 실행
pandas 행 이름 잃음유전자 ID가 0, 1, 2…로읽을 때 index_col=0. 열 기준 merge는 index를 버리니 left_index=True 등을 지정24
0·1 기반 번호 혼동한 칸씩 어긋남Python은 0부터, R은 1부터12. 좌표 파일은 8편

⚠️ 한계와 주의

  • 숫자의 범위: 노트북 연구 두 편은 주로 Python 노트북을 자동 재실행한 결과입니다. 2021년 연구는 생의학에 한정되지 않은 GitHub의 일반 노트북이라 오믹스 분석에 그대로 옮길 수 없습니다171.
  • 언어 자체의 우열을 보여 주는 근거는 없습니다. 같은 방법도 언어별 구현이 기본값과 결과를 다르게 낼 수 있으니, 논문에는 언어가 아니라 패키지 이름과 버전을 적습니다. DESeq2의 Python 구현(PyDESeq2)도 있는데, 개발진 스스로 R판과 비슷하지만 똑같지는 않은 결과를 낸다고 밝혔습니다. 섞어 쓰거나 비교할 때는 버전과 기본값을 함께 적으세요25.

🏛️ 지금 어디까지 왔나

  • 버전(2026-11-06 확인): Bioconductor 3.23(R 4.6), DESeq2 1.52.0, edgeR 4.10.7, limma 3.68.5, BiocManager 1.30.27, renv 1.3.1, reticulate 1.47.0, ggplot2 4.0.3 / pandas 3.1.1, numpy 2.5.4, scikit-learn 1.9.1, anndata 0.13.4, scanpy 1.12.5, rpy2 3.6.9, JupyterLab 4.6.5, Quarto 1.11.9.
  • 흐름: 두 언어를 잇는 도구가 늘고 있습니다. anndataR는 Bioconductor 3.22(2025년 10월)부터 포함됐고, Python 없이 R에서 h5ad를 읽고 쓰는 방법이 2026년 논문으로 나왔습니다826.
  • 한국: 국내 기관의 R·Python 교육·공용 분석 환경 현황은 확인하지 못했습니다.

🧪 연구자 노트

  • 언어는 쓰려는 도구가 어느 쪽에 있는지로 정하는 것이 현실적입니다. 벌크 RNA-seq 통계는 R(Bioconductor)이, 대규모 단일세포 처리나 머신러닝은 Python이 편한 경우가 많습니다.
  • 두 언어를 오가며 파일을 넘길 때는 행·열 방향과 시료 이름이 바뀌지 않았는지 꼭 확인하세요.

🙋 그래서 나에게는? — 실습 전 체크리스트

  • 쓰려는 핵심 패키지가 R·Python 중 어디에 있는지 먼저 확인했다
  • BiocManager::version()과 valid()로 릴리스가 하나인지 확인했다
  • 표를 읽은 뒤 행 이름(유전자 ID)과 시료 이름이 그대로인지 확인했다
  • renv.lock 또는 environment.yml, sessionInfo를 코드와 함께 git에 남긴다
  • 난수를 쓰는 단계에 시드를 정했고, 공유 전 노트북을 처음부터 다시 돌렸다

⚠️ 이 글은 의학적 조언이 아니며, 특정 제품을 권하지 않습니다. 실제 분석은 사용하는 패키지 설명서와 기관 SOP를 우선하세요.

❓ 자주 묻는 질문

Q. 처음 배운다면 하나만 고르면 되나요? A. 연구실이 이미 쓰는 언어와, 내 데이터에 필요한 핵심 패키지가 있는 언어를 먼저 배우세요. 다른 언어는 파일을 주고받을 정도만 익혀도 충분한 경우가 많습니다.

Q. conda로 R 패키지를 깔아도 되나요? A. 됩니다. 다만 bioconda 패키지 버전은 Bioconductor 릴리스와 다를 수 있고, 한 프로젝트 안에서 conda와 BiocManager 설치를 섞으면 어느 라이브러리에 깔렸는지 헷갈립니다. 한 방식으로 정하고 .libPaths()를 확인하세요.

Q. 노트북과 스크립트 중 무엇이 좋나요? A. 탐색과 설명에는 노트북, 반복 실행되는 단계에는 스크립트나 9편의 워크플로가 편합니다. 노트북도 처음부터 다시 돌려 확인하면 됩니다.

📚 오믹스 기술 시리즈

참고


  1. Samuel S, Mietchen D. Computational reproducibility of Jupyter notebooks from biomedical publications. GigaScience 2024;13:giad113. doi:10.1093/gigascience/giad113 ↩︎ ↩︎

  2. BiocManager vignette (BiocManager 1.30.27, 2026-11-06 확인) — cran.r-project.org ↩︎ ↩︎ ↩︎ ↩︎

  3. Bioconductor. Bioconductor 3.23 release announcement (2026-04-29) — bioconductor.org ↩︎

  4. Bioconductor. Bioconductor 3.24 release schedule (2026-11-06 확인) — bioconductor.org ↩︎

  5. SummarizedExperiment vignette (1.42.0, 2026-11-06 확인) — bioconductor.org ↩︎ ↩︎

  6. anndata. AnnData API (anndata 0.13.4, 2026-11-06 확인) — anndata.readthedocs.io ↩︎ ↩︎

  7. Scanpy documentation (scanpy 1.12.5, 2026-11-06 확인) — scanpy.readthedocs.io ↩︎

  8. Deconinck L 외. anndataR improves interoperability between R and Python in single-cell transcriptomics. Bioinformatics 2026;42:btag288. doi:10.1093/bioinformatics/btag288 ↩︎ ↩︎ ↩︎

  9. R documentation. read.table {utils} (R 4.6, 2026-11-06 확인) — stat.ethz.ch ↩︎ ↩︎

  10. pandas. pandas.read_csv (pandas 3.1.1, 2026-11-06 확인) — pandas.pydata.org ↩︎

  11. ggplot2. ggsave (ggplot2 4.0.3, 2026-11-06 확인) — ggplot2.tidyverse.org ↩︎

  12. reticulate. Arrays in R and Python (reticulate 1.47.0, 2026-11-06 확인) — rstudio.github.io/reticulate ↩︎ ↩︎

  13. rpy2. Interoperability with pandas (rpy2 3.6.9, 2026-11-06 확인) — rpy2.github.io ↩︎

  14. pandas. DataFrame.to_parquet (pandas 3.1.1, 2026-11-06 확인) — pandas.pydata.org ↩︎

  15. Posit. Positron FAQ (Positron 2026.11.0, 2026-11-06 확인) — positron.posit.co ↩︎

  16. Quarto. FAQ for R Markdown users (Quarto 1.11.9, 2026-11-06 확인) — quarto.org ↩︎

  17. Pimentel JF 외. Understanding and improving the quality and reproducibility of Jupyter notebooks. Empir Softw Eng 2021;26:65. doi:10.1007/s10664-021-09961-9 ↩︎ ↩︎

  18. nbconvert. Executing notebooks (2026-11-06 확인) — nbconvert.readthedocs.io ↩︎

  19. renv. Introduction to renv (renv 1.3.1, 2026-11-06 확인) — rstudio.github.io/renv ↩︎ ↩︎ ↩︎

  20. renv. snapshot (renv 1.3.1, type “implicit”, 2026-11-06 확인) — rstudio.github.io/renv ↩︎

  21. R documentation. sessionInfo {utils} (R 4.6, 2026-11-06 확인) — stat.ethz.ch ↩︎

  22. NumPy. Random sampling (numpy 2.5.4, 2026-11-06 확인) — numpy.org ↩︎

  23. pip. pip freeze (2026-11-06 확인) — pip.pypa.io ↩︎

  24. pandas. DataFrame.merge (pandas 3.1.1, 2026-11-06 확인) — pandas.pydata.org ↩︎

  25. Muzellec B 외. PyDESeq2: a python package for bulk RNA-seq differential expression analysis. Bioinformatics 2023;39(9):btad547. doi:10.1093/bioinformatics/btad547 ↩︎

  26. Bioconductor. anndataR (1.2.3, BioC 3.22부터 포함, 2026-11-06 확인) — bioconductor.org ↩︎