NumPy와 Pandas는 파이썬 데이터 분석의 핵심 라이브러리입니다.
NumPy는 수치 계산과 배열 연산을, Pandas는 표 형태의 데이터 처리를 담당합니다.
두 라이브러리 모두 내부적으로 C로 구현되어 있어 순수 파이썬보다 훨씬 빠릅니다.
pip install numpy pandas
NumPy
배열 생성
NumPy의 핵심 자료구조는 ndarray(n차원 배열)입니다.
import numpy as np
# 리스트로 배열 생성
arr = np.array([1, 2, 3, 4, 5])
print(arr) # [1 2 3 4 5]
print(arr.dtype) # int64
print(arr.shape) # (5,)
# 2차원 배열
matrix = np.array([[1, 2, 3],
[4, 5, 6]])
print(matrix.shape) # (2, 3) → 2행 3열
print(matrix.ndim) # 2
print(matrix.size) # 6 (전체 원소 수)
자주 사용하는 배열 생성 함수입니다.
np.zeros((3, 4)) # 0으로 채운 3×4 배열
np.ones((2, 3)) # 1로 채운 2×3 배열
np.eye(3) # 3×3 단위행렬
np.arange(0, 10, 2) # [0 2 4 6 8]
np.linspace(0, 1, 5) # [0. 0.25 0.5 0.75 1.] (균등 간격)
np.random.seed(42)
np.random.rand(3, 3) # 0~1 균등분포 난수 배열
np.random.randn(3, 3) # 표준정규분포 난수 배열
인덱싱과 슬라이싱
arr = np.array([10, 20, 30, 40, 50])
print(arr[0]) # 10
print(arr[-1]) # 50
print(arr[1:4]) # [20 30 40]
print(arr[::2]) # [10 30 50]
# 2차원 배열
matrix = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
print(matrix[0, 1]) # 2 (0행 1열)
print(matrix[1:, :2]) # [[4 5], [7 8]] (1행 이후, 0~1열)
print(matrix[:, 1]) # [2 5 8] (모든 행의 1열)
NumPy 슬라이싱은 복사본이 아닌 뷰(view)를 반환합니다. 슬라이싱된 배열을 수정하면 원본도 바뀝니다. 독립적인 복사본이 필요하면 .copy()를 사용합니다.
sub = matrix[0, :].copy()
불리언 인덱싱
조건으로 원소를 선택합니다. 데이터 필터링에서 자주 사용합니다.
arr = np.array([1.2, 3.5, 0.8, 4.1, 2.9])
mask = arr > 2.0
print(mask) # [False True False True True]
print(arr[mask]) # [3.5 4.1 2.9]
# 한 줄로 작성
print(arr[arr > 2.0])
연산
NumPy 배열은 원소 단위로 연산이 적용됩니다.
a = np.array([1, 2, 3, 4])
b = np.array([10, 20, 30, 40])
print(a + b) # [11 22 33 44]
print(a * b) # [10 40 90 160]
print(a ** 2) # [1 4 9 16]
print(a + 10) # [11 12 13 14] (브로드캐스팅)
브로드캐스팅
크기가 다른 배열 간 연산을 자동으로 확장합니다.
matrix = np.array([[1, 2, 3],
[4, 5, 6]])
row = np.array([10, 20, 30])
print(matrix + row)
# [[11 22 33]
# [14 25 36]]
집계 함수
arr = np.array([[1, 2, 3],
[4, 5, 6]])
print(arr.sum()) # 21 (전체 합)
print(arr.sum(axis=0)) # [5 7 9] (열 방향 합)
print(arr.sum(axis=1)) # [6 15] (행 방향 합)
print(arr.mean()) # 3.5
print(arr.std()) # 표준편차
print(arr.min(), arr.max())
print(arr.argmin(), arr.argmax()) # 최솟값, 최댓값의 인덱스
배열 변형
arr = np.arange(12)
reshaped = arr.reshape(3, 4) # 3×4로 변형
print(reshaped.shape) # (3, 4)
print(reshaped.flatten()) # 1차원으로 펼치기
print(reshaped.T) # 전치 (transpose)
생물정보학 예시
# 발현량 행렬: 행 = 유전자, 열 = 샘플
expression = np.array([
[12.5, 11.2, 13.8], # BRCA1
[8.3, 9.1, 7.6], # TP53
[21.0, 19.8, 22.3], # EGFR
])
# 각 유전자의 평균 발현량
gene_mean = expression.mean(axis=1)
print(gene_mean) # [12.5 8.33 21.03]
# 발현량 10 이상인 유전자 필터링
high_expr_idx = np.where(gene_mean >= 10)[0]
print(high_expr_idx) # [0 2]
# Z-score 정규화 (샘플 간 비교)
mean = expression.mean(axis=1, keepdims=True)
std = expression.std(axis=1, keepdims=True)
z_score = (expression - mean) / std
Pandas
Series와 DataFrame
Pandas의 두 핵심 자료구조는 Series(1차원)와 DataFrame(2차원)입니다.
import pandas as pd
# Series: 인덱스가 있는 1차원 배열
s = pd.Series([12.5, 8.3, 21.0], index=["BRCA1", "TP53", "EGFR"])
print(s)
# BRCA1 12.5
# TP53 8.3
# EGFR 21.0
# DataFrame: 표 형태의 2차원 구조
df = pd.DataFrame({
"sample_id": ["sample_01", "sample_02", "sample_03"],
"species": ["Homo sapiens", "Mus musculus", "Homo sapiens"],
"coverage": [30.5, 18.2, 45.8],
"gc_content":[0.512, 0.488, 0.521]
})
print(df)
파일 읽기·쓰기
# CSV 읽기
df = pd.read_csv("samples.csv")
df = pd.read_csv("samples.csv", index_col=0) # 첫 번째 열을 인덱스로
df = pd.read_csv("samples.csv", sep="\t") # TSV 읽기
# 파일 쓰기
df.to_csv("output.csv", index=False) # 인덱스 제외하고 저장
df.to_csv("output.tsv", sep="\t", index=False) # TSV로 저장
데이터 탐색
print(df.shape) # (행 수, 열 수)
print(df.dtypes) # 각 열의 데이터 타입
print(df.head()) # 상위 5행
print(df.tail(3)) # 하위 3행
print(df.info()) # 열 정보, 결측값 요약
print(df.describe()) # 수치형 열의 기술 통계
print(df.columns) # 열 이름 목록
print(df.index) # 인덱스 목록
열 선택과 행 선택
# 열 선택
print(df["coverage"]) # Series 반환
print(df[["sample_id", "coverage"]]) # DataFrame 반환
# loc: 레이블 기반 인덱싱
print(df.loc[0]) # 인덱스 0인 행
print(df.loc[0, "coverage"]) # 인덱스 0, coverage 열
print(df.loc[0:2, "sample_id":"coverage"]) # 범위 선택
# iloc: 위치 기반 인덱싱
print(df.iloc[0]) # 첫 번째 행
print(df.iloc[0, 2]) # 첫 번째 행, 세 번째 열
print(df.iloc[:3, :2]) # 0~2행, 0~1열
loc은 레이블(인덱스 이름, 열 이름) 기준, iloc은 정수 위치 기준입니다. loc의 슬라이싱은 끝 인덱스를 포함하지만, iloc은 포함하지 않습니다.
조건 필터링
# 단일 조건
high_cov = df[df["coverage"] >= 30]
# 복수 조건 (& : and, | : or)
filtered = df[(df["coverage"] >= 30) & (df["species"] == "Homo sapiens")]
# isin: 특정 값 목록에 포함 여부
target_species = ["Homo sapiens", "Mus musculus"]
df[df["species"].isin(target_species)]
# str 메서드로 문자열 필터링
df[df["sample_id"].str.startswith("sample_0")]
Pandas 조건식에서 and, or 대신 &, |를 사용하며, 각 조건을 반드시 괄호로 감싸야 합니다.
열 추가 및 수정
# 새 열 추가
df["gc_percent"] = df["gc_content"] * 100
df["is_human"] = df["species"] == "Homo sapiens"
# apply: 각 원소에 함수 적용
df["coverage_category"] = df["coverage"].apply(
lambda x: "high" if x >= 30 else "low"
)
결측값 처리
print(df.isnull().sum()) # 열별 결측값 수
print(df.isnull().any()) # 결측값이 있는 열 확인
df.dropna() # 결측값이 있는 행 제거
df.dropna(subset=["coverage"]) # 특정 열에 결측값 있는 행 제거
df.fillna(0) # 결측값을 0으로 채우기
df["coverage"].fillna(df["coverage"].mean()) # 평균으로 채우기
그룹화와 집계
# groupby: 특정 열 기준으로 그룹화 후 집계
grouped = df.groupby("species")["coverage"].mean()
print(grouped)
# 여러 집계 함수 동시 적용
df.groupby("species")["coverage"].agg(["mean", "std", "min", "max"])
# 여러 열 집계
df.groupby("species").agg({
"coverage": "mean",
"gc_content": "std"
})
정렬
df.sort_values("coverage") # 오름차순
df.sort_values("coverage", ascending=False) # 내림차순
df.sort_values(["species", "coverage"], ascending=[True, False]) # 다중 열 정렬
유용한 메서드
df["species"].value_counts() # 값별 빈도 계산
df["coverage"].unique() # 고유값 목록
df["coverage"].nunique() # 고유값 수
df.duplicated() # 중복 행 확인
df.drop_duplicates() # 중복 행 제거
df.rename(columns={"gc_content": "gc"}) # 열 이름 변경
df.drop(columns=["gc_content"]) # 열 삭제
df.reset_index(drop=True) # 인덱스 초기화
데이터 병합
# merge: SQL JOIN과 유사
df1 = pd.DataFrame({"id": ["s01", "s02"], "coverage": [30.5, 18.2]})
df2 = pd.DataFrame({"id": ["s01", "s02"], "gc": [0.51, 0.49]})
merged = pd.merge(df1, df2, on="id") # inner join (기본)
merged = pd.merge(df1, df2, on="id", how="left") # left join
# concat: 단순 연결
pd.concat([df1, df2], axis=0) # 행 방향으로 연결
pd.concat([df1, df2], axis=1) # 열 방향으로 연결
NumPy와 Pandas 함께 사용하기
# DataFrame의 수치형 열을 NumPy 배열로 변환
values = df[["coverage", "gc_content"]].values # ndarray 반환
print(type(values)) # <class 'numpy.ndarray'>
# NumPy 연산 후 DataFrame에 추가
df["log_coverage"] = np.log2(df["coverage"])
df["normalized"] = (df["coverage"] - df["coverage"].mean()) / df["coverage"].std()
정리표
| 항목 | Numpy | Pandas |
| 핵심 자료구조 | ndarray | Series, DataFrame |
| 주요 용도 | 수치 계산, 행렬 연산 | 표 형태 데이터 처리 |
| 인덱싱 | arr[행, 열] | loc(레이블), iloc(위치) |
| 파일 읽기 | - | pd.read_csv() |
| 집계 | arr.mean(axis=) | groupby().agg() |
| 결측값 | - | fillna(), dropna() |
'BI&Programming-Tools > Python' 카테고리의 다른 글
| [파이썬 기초] 통계 기초 (scipy) (0) | 2026.06.19 |
|---|---|
| [파이썬 기초] Matplotlib / Seaborn 시각화 (0) | 2026.06.18 |
| [파이썬 기초] 클래스, 모듈, 예외처리 (0) | 2026.06.18 |
| [파이썬 기초] 파일 형식 처리 (CSV, TSV, FASTA) (0) | 2026.06.17 |
| [파이썬 기초] 변수 범위와 파일 읽기·쓰기 (0) | 2026.06.17 |
