[Pandas] 성능 / 메모리 최적화
Pandas 성능 / 메모리 최적화, Pandas performance, Pandas memory, pandas 최적화, pandas 빠르게
정의
pandas 의 흔한 성능 함정과 최적화 패턴. 벡터화 + dtype 선택 + 알고리즘 의 조합이 핵심.
1. 벡터 연산 우선
# ❌ Python loop (느림)
for i in range(len(df)):
df.iloc[i, 0] = df.iloc[i, 1] * 2
# ❌ apply 행마다 (좀 느림)
df['c'] = df.apply(lambda r: r['a'] * r['b'], axis=1)
# ✓ 벡터 연산 (빠름)
df['c'] = df['a'] * df['b']
100배 이상 차이.
2. dtype 명시로 메모리 절약
python
import pandas as pd
import numpy as np
n = 1_000_000
df = pd.DataFrame({
'id': np.arange(n),
'small_int': np.random.randint(0, 100, n),
'category': np.random.choice(['A','B','C','D'], n),
})
print('기본:', df.memory_usage(deep=True).sum() // 1024, 'KB')
# 최적화
df['id'] = df['id'].astype('int32')
df['small_int'] = df['small_int'].astype('int8')
df['category'] = df['category'].astype('category')
print('최적화:', df.memory_usage(deep=True).sum() // 1024, 'KB') 결과
기본: 64453 KB
최적화: 4889 KB13 배 절감. 작은 dtype 가능 여부 확인.
| 정수 범위 | dtype |
|---|---|
| -128 ~ 127 | int8 |
| -32,768 ~ 32,767 | int16 |
| 약 ±21억 | int32 |
| 그 이상 | int64 |
pd.api.types.infer_dtype 또는 df.info(memory_usage='deep') 로 점검.
3. category dtype 활용
문자 컬럼에서 고유값이 적으면 Pandas Categorical 로 변환. 메모리 + groupby/merge 속도 모두 개선.
df['city'] = df['city'].astype('category')
4. inplace vs assign
df.sort_values('age', inplace=True) # 옛날엔 빠르다고 했지만
df = df.sort_values('age') # 사실 비슷, 명시성 좋음
inplace 가 메모리 절약 효과가 거의 없는 경우가 많다 (내부 복사 발생).
5. read_csv 의 최적화
df = pd.read_csv('big.csv',
usecols=['a', 'b', 'c'], # 필요한 컬럼만
dtype={'a': 'int32', 'b': 'category'},
parse_dates=['ts'],
)
chunksize= 로 스트리밍.
6. 큰 데이터는 Parquet
df.to_parquet('out.parquet')
df = pd.read_parquet('out.parquet')
CSV 대비 수십 배 빠르고 작다, dtype 도 보존.
7. eval / query (numexpr 가속)
# 큰 DataFrame 에서
df.eval('total = price * qty + tax')
df.query('age > 30 and city == "Seoul"')
작은 DataFrame 에는 오히려 느릴 수 있음 (parser 비용).
8. groupby 의 cython 경로 사용
df.groupby('x')['y'].sum() # cython, 빠름
df.groupby('x')['y'].apply(sum) # Python apply, 느림
agg / 내장 메서드가 apply 보다 훨씬 빠르다.
9. 인덱스 활용
df = df.set_index('user_id').sort_index()
df.loc[12345] # O(log n) 또는 O(1)
df[df['user_id'] == 12345] # O(n) scan
자주 lookup 하는 키를 index 로.
10. merge 시 dtype/sort 확인
# 양쪽 키가 같은 dtype 인지
left['id'] = left['id'].astype('int64')
right['id'] = right['id'].astype('int64')
# 정렬되어 있으면 merge 가 빠름
pd.merge(left.sort_values('id'), right.sort_values('id'), on='id')
11. swifter / modin / polars (외부 도구)
swifter: pandas 의 apply 를 자동 병렬화modin: pandas API 호환 + 멀티코어polars: Arrow 기반, 종종 10-100배 빠름
큰 데이터에서 pandas 의 한계를 만나면 검토.
12. info / memory_usage / describe 활용
df.info(memory_usage='deep')
df.memory_usage(deep=True).sort_values(ascending=False)
어느 컬럼이 메모리를 많이 쓰는지 확인.
함정
1. chained indexing
df['col'][idx] = 1 # ⚠️ view 일지 copy 일지 모호
df.loc[idx, 'col'] = 1 # ✓ 한 줄 indexer
2. concat in loop
result = pd.DataFrame()
for chunk in chunks:
result = pd.concat([result, chunk]) # ❌ O(n²)
# ✓ 한 번에
result = pd.concat(chunks)
3. apply 의 axis=1
df.apply(fn, axis=1)
# 행마다 Python 함수 호출, 가장 느린 패턴
벡터 연산 / 내장 메서드로 표현 가능한지 먼저 확인.
참고
이 글의 용어 (3개)
- [Pandas] Categoricalpandas
- 정의 Categorical 은 제한된 고유값 만 가질 수 있는 dtype. 내부적으로 정수 코드로 저장되어 메모리 절약 과 속도 향상. 사용 <CodeWithOutput lang…
- [Pandas] DataFramepandas
- 정의 은 2차원 레이블 테이블. 각 열이 , 모든 열이 같은 (행 라벨) 를 공유. SQL 테이블 / Excel 시트 / R data.frame 의 Python 대응체. 생성 <…
- [Pandas] read_csv / to_csvpandas
- 정의 는 CSV (Comma-Separated Values) 파일 또는 비슷한 텍스트 형식을 으로 읽는 함수. pandas 사용의 99% 가 여기서 시작. 대응 출력 함수는 . …
💬 댓글