BioPlayground

🧬
목록으로

Pandas로 실험 데이터 정리하기

Pandas DataFrame으로 CSV 실험 데이터를 읽고, 필터링하고, 그룹별 통계를 구하는 법.

중급
|
90
|
검증 완료 (2026-06)
pandasDataFrameCSV데이터 정리groupbymerge
트랙 진행률0/5 (0%)

Pandas로 실험 데이터 정리하기

이 토픽을 마치면

Pandas DataFrame으로 CSV를 읽고, 조건부 필터링을 하고, 그룹별 통계를 구하고, 두 테이블을 합칠 수 있습니다.


Pandas란

앞 토픽에서 csv 모듈로 파일을 읽고 반복문으로 처리하는 법을 배웠습니다. 시료 10개면 충분하지만, 시료가 5,000개이고 컬럼이 50개라면 반복문으로는 힘듭니다.

Pandas는 표 형태 데이터를 다루는 Python 라이브러리입니다. 엑셀 시트와 비슷한 DataFrame 구조에 데이터를 넣고, 필터링/정렬/집계를 한 줄로 처리합니다.

실험 노트에서 비유하면 — csv 모듈이 노트를 한 줄씩 읽는 것이라면, Pandas는 전체 표를 한눈에 펼쳐놓고 원하는 열/행을 즉시 꺼내는 것입니다.

DataFrame 만들기

python
import pandas as pd
df = pd.read_csv("expression_data.csv")
print(df)
print(f"\n행: {len(df)}, 열: {len(df.columns)}")
print(f"컬럼: {list(df.columns)}")

pd.read_csv() 한 줄로 CSV 파일이 DataFrame이 됩니다. csv.DictReader와 반복문 없이도 전체 데이터가 로드됩니다.

직접 데이터를 만들 수도 있습니다:

python
import pandas as pd
data = {
"sample_id": ["S001", "S002", "S003", "S004", "S005"],
"gene": ["EGFR", "TP53", "EGFR", "BRCA1", "TP53"],
"expression": [12.5, 3.2, 18.7, 7.1, 2.8],
"status": ["high", "low", "high", "medium", "low"],
}
df = pd.DataFrame(data)
print(df)

출력:

text
sample_id   gene  expression  status
0      S001   EGFR        12.5    high
1      S002   TP53         3.2     low
2      S003   EGFR        18.7    high
3      S004  BRCA1         7.1  medium
4      S005   TP53         2.8     low

데이터 살펴보기

DataFrame을 처음 받으면 전체 모습을 빠르게 파악합니다:

python
df.head() # 앞 5행
df.tail(3) # 뒤 3행
df.shape # (행 수, 열 수)
df.dtypes # 각 열의 데이터 타입
df.describe() # 숫자 열의 기본 통계 (평균, 표준편차, 최솟값, 최댓값)

df.describe()는 실험 결과를 처음 받았을 때 "대충 어떤 범위인가?" 파악하는 데 유용합니다.

열/행 선택

python
# 열 하나 선택 — Series 반환
genes = df["gene"]
# 열 여러 개 선택 — DataFrame 반환
subset = df[["sample_id", "expression"]]
# 행 선택 — 인덱스로
first_row = df.iloc[0] # 첫 번째 행
first_three = df.iloc[0:3] # 0~2번째 행

조건부 필터링

Pandas의 핵심 기능입니다. csv 모듈에서 for문 + if문으로 했던 것을 한 줄로 합니다:

python
# EGFR 유전자만
egfr = df[df["gene"] == "EGFR"]
print(egfr)
# expression이 5 이상인 시료
high_expr = df[df["expression"] >= 5.0]
print(high_expr)
# 복합 조건: EGFR이면서 expression이 15 이상
egfr_high = df[(df["gene"] == "EGFR") & (df["expression"] >= 15.0)]
print(egfr_high)
assert len(egfr) == 2
assert len(egfr_high) == 1

&는 AND, |는 OR입니다. 각 조건을 괄호로 감싸야 합니다.

정렬

python
# expression 내림차순
sorted_df = df.sort_values("expression", ascending=False)
print(sorted_df)

그룹별 집계: groupby

"유전자별 평균 발현량은?" — 엑셀에서 피벗 테이블로 하던 것을 groupby로 합니다:

python
gene_stats = df.groupby("gene")["expression"].agg(["mean", "std", "count"])
print(gene_stats)

출력:

text
mean       std  count
gene
BRCA1   7.10       NaN      1
EGFR   15.60  4.384062      2
TP53    3.00  0.282843      2

groupby("gene") — 유전자별로 묶고, ["expression"] — expression 열에 대해, agg(["mean", "std", "count"]) — 평균, 표준편차, 개수를 한번에 계산합니다.

새 열 추가

python
# expression을 log2로 변환한 열 추가
import numpy as np
df["log2_expression"] = np.log2(df["expression"])
print(df[["sample_id", "expression", "log2_expression"]])

두 테이블 합치기: merge

실험 데이터와 시료 정보가 별도 파일에 있을 때:

python
import pandas as pd
# 시료 메타데이터
metadata = pd.DataFrame({
"sample_id": ["S001", "S002", "S003", "S004", "S005"],
"tissue": ["lung", "breast", "lung", "breast", "colon"],
"age": [45, 62, 38, 55, 71],
})
# expression 데이터와 합치기
merged = pd.merge(df, metadata, on="sample_id")
print(merged)

on="sample_id" — 두 테이블에서 같은 값을 가진 행끼리 합칩니다. SQL의 JOIN과 같은 개념입니다. database-basics 토픽에서 배운 것이 여기서도 통합니다.

결과 저장

python
# CSV로 저장
egfr.to_csv("egfr_samples.csv", index=False)
# TSV로 저장
egfr.to_csv("egfr_samples.tsv", sep="\t", index=False)

index=False — 행 번호(0, 1, 2...)를 파일에 포함하지 않습니다.

직접 해보기 (Faded Example)

아래 빈칸을 채워 DataFrame에서 조건부 필터링과 그룹 집계를 수행하세요.

빈칸 채우기python
import pandas as pd
df = pd.read_csv("samples.csv")
# OD가 1.0 이상인 시료 필터링
passed = df[df["od"] 1.0]
# 상태별 평균 OD
stats = df.("status")["od"].mean()
print(stats)

흔한 에러 & 해결법

Q: KeyError: 'gene' 에러가 납니다

컬럼 이름이 정확한지 확인하세요. df.columns로 실제 컬럼 이름을 출력해보세요. 공백이 포함되어 있을 수 있습니다 (" gene" vs "gene").

Q: 필터링했는데 빈 DataFrame이 나옵니다

조건이 너무 엄격하거나 데이터 타입이 맞지 않을 수 있습니다. df["expression"].dtype으로 타입을 확인하세요. 문자열을 숫자로 비교하면 결과가 없을 수 있습니다.

Q: SettingWithCopyWarning 경고가 뜹니다

필터링한 결과에 값을 할당할 때 나오는 경고입니다. df_filtered = df[조건].copy()로 명시적 복사본을 만든 뒤 수정하면 경고가 사라집니다.

Q: merge 했는데 행 수가 늘어났습니다

on으로 지정한 열에 중복 값이 있으면 모든 조합이 만들어져 행이 늘어납니다. merge 전에 양쪽 테이블에서 df["sample_id"].duplicated().sum()으로 중복을 확인하세요.