본문으로 건너뛰기
김신건의 로그

[Pandas] 성능 / 메모리 최적화

· 수정 · 📖 약 1분 · 400자/단어 #python #pandas #performance #memory #optimization
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 KB

13 배 절감. 작은 dtype 가능 여부 확인.

정수 범위dtype
-128 ~ 127int8
-32,768 ~ 32,767int16
약 ±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% 가 여기서 시작. 대응 출력 함수는 . …

💬 댓글

사이트 검색 / 명령어

검색

스크롤 = 확대/축소 · 드래그 = 이동 · 0 = 원래 크기 · ESC = 닫기