Pandas 성능 최적화 가이드: 2024년 Polars 또는 DuckDB로 전환해야 할 시점과 방법

Pandas 성능 한계를 분석하고 최적화 기법을 소개합니다. Polars와 DuckDB의 특징, 벤치마크 비교, 전환 시점과 마이그레이션 전략을 상세히 설명합니다.

  • MIT
  • 업데이트 2026-05-18

{</* resource-info */>}

Python 데이터 처리의 표준 라이브러리인 Pandas는 2008년 출시 이후 15년 이상 데이터 사이언스 생태계의 중심에 있었습니다. 하지만 데이터 규모가 GB 단위를 넘어서면서 성능 한계가 두드러지고 있습니다. 본 가이드에서는 Pandas 최적화 기법부터 차세대 대안인 Polars와 DuckDB의 도입 시점과 전략을 상세히 분석합니다.

Pandas가 대용량 데이터에서 어려움을 겪는 이유 #

Pandas의 성능 병목 현상은 아키텍처적 특성에서 비롯됩니다. 첫째, 단일 스레드로만 연산을 처리하여 멀티코어 CPU를 활용하지 못합니다. 둘째, Eager Evaluation(즉시 평가) 방식으로 중간 결과를 모두 메모리에 적재합니다. 셋째, Apache Arrow 기반이 아닌 NumPy 배열 기반으로 설계되어 메모리 효율이 현대적 도구에 비해 떨어집니다.

실제 1GB CSV 파일을 처리하는 벤치마크에서 Pandas는 평균 45초가 소요되며, 피크 메모리 사용량은 파일 크기의 5~10배에 달합니다. 10GB 이상 데이터셋에서는 메모리 부족 오류가 빈번하게 발생합니다. 이러한 한계는 2015년 이전 설계 철학이 반영된 구조적 문제로, 코드 수준 최적화로는 근본적인 해결이 어렵습니다.

Pandas 최적화 기법: 전환 전에 시도할 수 있는 방법 #

더 빠른 도구로 전환하기 전, Pandas 자체에서 성능을 끌어올리는 방법을 먼저 시도하는 것이 효율적입니다. 다음 기법들은 기존 코드베이스를 유지하면서 성능 향상을 도모합니다.

코드 수준 최적화 #

  • 벡터화 연산: apply() 대신 내장 벡터 함수를 사용하면 10~100배 성능 향상을 얻을 수 있습니다. 예를 들어 df['col'].apply(lambda x: x*2) 대신 df['col'] * 2를 사용하세요.
  • eval()과 query() 활용: 문자열 기반 표현식은 Numexpr 엔진을 통해 성능이 최적화됩니다. df.query('age > 30 & city == "Seoul"') 형태가 복수 조건 필터링에서 더 효율적입니다.
  • 체인 인덱싱 회피: df[a][b] 대신 df.loc[a, b]를 사용하여 중간 복사본 생성을 방지합니다.
  • 효율적인 병합: merge() 호출 시 howon 파라미터를 명시적으로 지정하고, 필요한 열은 미리 설정합니다.
  • Categorical dtype 변환: 반복 값이 많은 열은 astype('category')로 변환하면 메모리 사용량을 70% 이상 줄일 수 있습니다.

파일 형식과 메모리 관리 #

Parquet 형식으로 데이터를 저장하면 CSV 대비 75% 이상 디스크 공간을 절약하고, 읽기 속도가 2~5배 빠릅니다. memory_profiler 패키지를 활용하여 함수 단위 메모리 사용량을 추적하고 병목 지점을 식별하세요. 대용량 파일은 chunksize 파라미터로 분할 처리하는 것도 효과적입니다.

Polars: Rust 기반 데이터프레임 혁명 #

Polars는 Rust 언어로 작성된 오픈소스 데이터프레임 라이브러리로, Apache Arrow 메모리 형식을 기반으로 합니다. 2020년 첫 출시 이후 GitHub에서 30,000개 이상의 스타를 획득했으며(2024년 12월 기준), 데이터 처리 성능 벤치마크에서 일관적으로 상위권을 기록하고 있습니다.

Polars의 핵심 특징 #

  • 멀티스레드 기본 지원: 모든 연산이 CPU 코어 수에 비례하여 가속됩니다
  • Lazy Evaluation: 쿼리 최적화 엔진이 실행 계획을 자동으로 최적화합니다
  • Streaming Mode: 메모리보다 큰 데이터셋도 디스크 버퍼링으로 처리 가능합니다
  • Arrow 기반 메모리: 제로카피 전환으로 Pandas와의 호환성을 유지합니다

Polars Lazy API와 Streaming #

Polars는 Eager API와 Lazy API를 모두 제공합니다. 1GB 이하 데이터는 Eager가 직관적이지만, 그 이상에서는 Lazy API가 필수입니다. pl.scan_csv('large_file.csv')로 시작하면 쿼리 최적화기가 조건을 소스에 가깝게 밀어넣어(Predicate Pushdown) 불필요한 데이터 로드를 방지합니다. streaming=True 옵션을 추가하면 100GB 데이터셋도 16GB RAM으로 처리 가능합니다.

DuckDB: 인프라 없는 OLAP 데이터베이스 #

DuckDB는 2019년 톰헨(CWI)에서 개발을 시작한 인프라스트럭처가 불필요한(In-Process) OLAP 데이터베이스입니다. 별도 서버 설치 없이 Python 라이브러리로 pip install duckdb 한 줄로 설치할 수 있습니다.

DuckDB의 핵심 특징 #

DuckDB는 비용 기반 쿼리 최적화기(Cost-Based Optimizer)와 벡터화 실행 엔진을 탑재하고 있습니다. PostgreSQL, MySQL, SQLite에 직접 연결하여 SQL로 원격 데이터를 조회할 수 있으며, Parquet 파일을 SQL 테이블처럼 직접 쿼리하는 기능이 강력합니다. Pandas DataFrame 위에 SQL을 실행할 수도 있어 마이그레이션 부담이 최소화됩니다.

DuckDB와 Pandas 통합 패턴 #

import duckdb
import pandas as pd

df = pd.read_csv('data.csv')
# Pandas DataFrame에 SQL 직접 실행
result = duckdb.query("SELECT * FROM df WHERE value > 100").to_df()

이러한 호환성 덕분에 기존 Pandas 파이프라인에서 점진적으로 DuckDB를 도입할 수 있습니다. Parquet 파일도 read_parquet()로 직접 읽고, 윈도우 함수나 CTE(공통 테이블 표현식)로 Pandas에서는 복잡한 연산을 간결하게 표현할 수 있습니다.

벤치마크 비교: Pandas vs Polars vs DuckDB #

연산Pandas 2.1Polars 1.0DuckDB 1.0데이터 크기
CSV 읽기28.5초3.2초4.1초1GB
필터링4.2초0.3초0.4초1GB (메모리)
GroupBy 집계12.8초1.1초1.5초1GB
Join (1M x 1M)35.2초2.8초3.5초1억 행
메모리 사용량8.2GB2.1GB1.8GB1GB CSV 기준
10GB+ 처리메모리 오류Streaming 지원Streaming 지원10GB CSV

출처: Polars 공식 벤치마크, h2oai 벤치마크 결과 기준

시나리오별 도구 선택 기준 #

  • EDA 워크플로우: 작은 데이터셋(< 1GB)에서는 Pandas가 여전히 적합합니다. 5GB 이상부터 Polars Lazy API를 고려하세요.
  • ETL 파이프라인: Polars의 Streaming Mode가 안정적이며, 파일 기반 ETL에서는 DuckDB의 SQL 직관성이 장점입니다.
  • 대규모 분석: 100GB 이상 데이터는 Polars 또는 DuckDB의 스트리밍 기능이 필수적입니다.
  • ML 특성 엔지니어링: Pandas와의 호환성이 중요하면 DuckDB, 새로운 파이프라인 구축이라면 Polars가 적합합니다.
  • 실시간 쿼리: DuckDB의 인덱싱과 쿼리 최적화기가 응답 시간을 단축시킵니다.

마이그레이션 전략과 상호운용성 #

전체 코드베이스를 한 번에 옮기는 대신 점진적 마이그레이션을 권장합니다. 첫 번째 접근법은 I/O 병목 구간만 교체하는 것입니다. CSV 읽기와 기본 필터링을 Polars로 대체하고, 후속 분석은 Pandas와 호환되는 Arrow 형식으로 전달합니다.

두 번째 접근법은 DuckDB를 Pandas 파이프라인 중간에 삽입하는 패턴입니다. 복잡한 SQL 연산은 DuckDB에 위임하고 결과를 .to_df()로 Pandas에 반환합니다. 이 방식은 기존 코드를 최소한으로 수정하면서 성능 향상을 얻을 수 있습니다.

세 번째는 Polars의 to_pandas() 메서드를 활용한 단계적 전환입니다. 팀원들이 Polars 문법에 익숙해지는 기간을 두고, 모듈별로 순차적으로 전환하세요.

자주 묻는 질문 #

Polars는 Pandas를 완전히 대체할 수 있나요? #

Polars는 Pandas의 대부분 핵심 기능을 지원하지만, 완전한 드롭인 교체는 아닙니다. API 문법이 다륾고(df.filter() 대신 df[df.col > 0]), 일부 Pandas의 복잡한 다중 인덱스 기능은 Polars의 단순한 설계 철학과 맞지 않습니다. 하지만 2024년 기준 주요 ML 라이브러리(scikit-learn, XGBoost 등)는 Polars DataFrame을 Arrow를 통해 직접 수용합니다.

DuckDB 대신 Polars를 선택해야 할 때는 언제인가요? #

새로운 파이프라인을 구축하거나 복잡한 데이터 변환 체인이 필요할 때는 Polars가 적합합니다. SQL 문법에 익숙하고 관계형 데이터 분석이 주요 워크플로우라면 DuckDB가 더 직관적입니다. 두 도구는 상호 보완적이며, 실제로 Polars는 남적으로 DuckDB를 백엔드로 사용할 수 있는 통합 옵션도 제공합니다.

Polars와 DuckDB를 함께 사용할 수 있나요? #

네, 가능합니다. Polars의 scan_parquet()는 DuckDB에서 생성한 Parquet 파일을 읽을 수 있으며, 반대로 DuckDB는 Polars DataFrame을 SQL 쿼리의 입력으로 직접 사용할 수 있습니다. 일부 프로젝트에서는 데이터 로딩은 DuckDB(SQL)로, 복잡한 변환은 Polars(Lazy API)로, 최종 모델 입력은 Pandas로 처리하는 하이브리드 파이프라인을 구성합니다.

Polars는 Pandas보다 얼마나 빠른가요? #

연산 유형에 따라 다르지만, 일반적으로 530배 빠릅니다. CSV 읽기는 810배, GroupBy 집계는 1015배, 복수 조건 필터링은 1520배 성능 향상을 보입니다. 멀티코어 CPU를 가득 활용하는 연산일수록 차이가 커집니다. 단순 연산에서는 차이가 작고, 복잡한 체인 연산에서는 Lazy Evaluation의 쿼리 최적화 효과가 극대화됩니다.

초보자는 Pandas와 Polars 중 무엇부터 배워야 하나요? #

2024년 현재 Pandas가 여전히 표준입니다. 온라인 튜토리얼, Stack Overflow 답변, 대부분의 데이터 사이언스 교재가 Pandas 기준으로 작성되어 있습니다. Pandas에 익숙해진 후(약 3~6개월) Polars를 추가로 학습하는 것이 현실적입니다. 하지만 새로 시작하는 팀이 성능이 중요한 프로젝트를 시작한다면, Polars부터 배우는 것도 유효한 전략입니다. Polars API는 Pandas보다 일관성 있게 설계되어 학습 곡선이 오히려 완만할 수 있습니다.

결론 #

Pandas는 Python 데이터 처리의 기준으로 남아있지만, 1GB를 넘어서는 데이터에서는 Polars나 DuckDB로의 전환을 고려해야 합니다. 코드 수준 최적화로 해결 가능한 문제인지, 아니면 아키텍처 한계인지를 먼저 판단하세요. Polars는 새로운 고성능 파이프라인 구축에, DuckDB는 SQL 친화적 분석 환경에 각각 최적화되어 있습니다. 두 도구는 Pandas와도 원활하게 상호운용되므로, 기존 코드베이스를 점진적으로 개선하는 전략이 가장 현실적입니다.


추천 인프라 #

위 도구들을 24/7 안정 운영하려면 인프라가 중요하다:

  • DigitalOcean — 신규 가입 시 $200 크레딧 60일, 글로벌 14+ 리전.
  • HTStack — 홍콩 VPS, 중국 본토 저지연. dibi8.com 자체 호스팅 IDC.

추천 링크 — 추가 비용 없이 dibi8.com을 지원합니다.

💬 댓글 토론