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

[Pandas] PyArrow Backend

· 수정 · 📖 약 2분 · 566자/단어 #python #pandas #pyarrow #arrow #performance
Pandas pyarrow backend, Pandas pyarrow, Pandas arrow, Pandas 2.0 arrow

정의

pandas 2.0 부터 Apache Arrow 를 백킹으로 사용 하는 새 dtype 시스템. NumPy 기반의 한계 (메모리, 문자열, 타입 다양성) 를 크게 개선.

사용 상황

상황pyarrow backend 이점
대용량 문자열 컬럼메모리 1/10 수준 절감
Parquet 읽기/쓰기Arrow - Parquet 직접 매핑, 변환 비용 없음
int + NaN 공존NumPy 는 float 으로 강등, Arrow 는 native int
중첩 타입 (list, struct)NumPy 불가, Arrow 는 가능
정확한 소수 (decimal)Arrow decimal 타입 지원
Python 3.x 마이그레이션 준비pandas 3.0 은 Arrow 기본 예정

시각화

NumPy vs Arrow 메모리 레이아웃 비교:

flowchart LR
    NP["NumPy Backend"]
    AR["Arrow Backend"]
    NP --> NP1["string: Python object 포인터 배열"]
    NP --> NP2["int + NaN: float64 로 강등"]
    NP --> NP3["중첩 타입: 지원 없음"]
    AR --> AR1["string: 연속 바이트 버퍼 + 오프셋"]
    AR --> AR2["int + NA: 비트마스크 분리 저장"]
    AR --> AR3["list, struct: 네이티브 지원"]

마이그레이션 경로:

flowchart TD
    Old["기존 NumPy dtype DataFrame"]
    Old --> A["read 시점 변환: dtype_backend='pyarrow'"]
    Old --> B["명시적 변환: convert_dtypes(dtype_backend='pyarrow')"]
    Old --> C["개별 컬럼: astype('int64[pyarrow]')"]
    A --> New["Arrow dtype DataFrame"]
    B --> New
    C --> New
    New --> Compat["기존 pandas API 대부분 호환"]

적용 방법

1. read 함수에서

df = pd.read_csv('data.csv', dtype_backend='pyarrow')
df = pd.read_parquet('data.parquet', dtype_backend='pyarrow')
df.dtypes
# id        int64[pyarrow]
# name      string[pyarrow]
# ts        timestamp[ns, UTC][pyarrow]

2. 전역 설정

pd.options.future.infer_string = True       # 문자열은 pyarrow 로 추론

3. 명시적 변환

df = df.astype({
    'id': 'int64[pyarrow]',
    'name': 'string[pyarrow]',
})
df = df.convert_dtypes(dtype_backend='pyarrow')   # 자동 변환

NumPy backend vs pyarrow backend

항목NumPypyarrow
int + NaN✗ (float 강등)
stringobject (Python list)native arrow string
datetime tz✓ (정밀)
decimal
nested types (list, struct)
메모리 (string)~1/10
Parquet IO변환 비용직접
GIL 회피

메모리 비교 예

python
import pandas as pd
import numpy as np
np.random.seed(0)

n = 100_000
df = pd.DataFrame({
  'city': np.random.choice(['Seoul','Busan','Daegu'], n),
  'plan': np.random.choice(['basic','pro','premium'], n),
})

print('object:', df.memory_usage(deep=True).sum() // 1024, 'KB')
df_arrow = df.astype({'city': 'string[pyarrow]', 'plan': 'string[pyarrow]'})
print('arrow :', df_arrow.memory_usage(deep=True).sum() // 1024, 'KB')
결과
object: 12302 KB
arrow : 791 KB

15 배 절감.

문자열 처리 속도

# str accessor 메서드는 그대로 사용
df['name'].str.upper()
df['name'].str.contains('python')
df['name'].str.split(',')

pyarrow backend 에서는 내부 구현이 더 빠르다.

정밀한 타입

# DECIMAL 타입 (정확한 소수)
df = pd.DataFrame({'price': pd.array(['1.23', '4.56'], dtype='decimal128(10, 2)[pyarrow]')})

# timezone 인식 timestamp
df['ts'].dt.tz                # arrow 는 더 정확한 timezone 표현

단점 / 함정

1. 일부 메서드 호환성

대부분의 pandas API 가 동작하지만, 일부 (특히 사용자 함수 적용) 에서 fallback 발생. 점진적으로 개선 중.

2. 다른 라이브러리와의 호환

# scikit-learn 입력
X = df.values            # numpy 로 변환 (arrow → numpy 복사)
# 큰 데이터에서 비용 발생 가능

ML 파이프라인에 들어갈 때는 변환 단계가 비용일 수 있다.

3. 일부 dtype 의 표현

pd.array([1, 2, 3], dtype='int64[pyarrow]')[0]
# ArrayScalar(1) 같은 형태로 보일 수 있음

스칼라 표현이 NumPy 와 다를 수 있음.

4. NaN vs <NA>

df['x'].astype('int64[pyarrow]')
# NaN 위치 → <NA>
df['x'].isna()                # 양쪽 모두 처리

자주 쓰는 패턴

1. Parquet pipeline

df = pd.read_parquet('data.parquet', dtype_backend='pyarrow')
result = process(df)
result.to_parquet('out.parquet')

Arrow → pandas → Arrow 변환 비용 거의 없음.

2. 문자열 대용량 데이터

df = pd.read_csv('logs.csv', dtype_backend='pyarrow')
# string[pyarrow] 가 메모리 1/10
df['message'].str.contains('ERROR').sum()

3. 점진적 마이그레이션

df = df.convert_dtypes(dtype_backend='pyarrow')
# 기존 NumPy dtype → 적절한 arrow dtype 변환

dtype 변환 상세

NumPy dtypeArrow dtype
object (문자열)string[pyarrow]
int64int64[pyarrow]
float64double[pyarrow]
boolbool[pyarrow]
datetime64[ns]timestamp[ns][pyarrow]
categorydictionary[pyarrow]
# 개별 컬럼 변환
df['name'] = df['name'].astype('string[pyarrow]')
df['count'] = df['count'].astype('int64[pyarrow]')

# 전체 일괄 변환
df_arrow = df.convert_dtypes(dtype_backend='pyarrow')

# dtype 확인
df_arrow.dtypes
# id      int64[pyarrow]
# name    string[pyarrow]

ML 파이프라인 연동

Arrow backend 로 메모리를 절약한 뒤, ML 단계에서는 NumPy 로 변환:

# 1. 대용량 데이터: Arrow 로 로드
df = pd.read_parquet('big_data.parquet', dtype_backend='pyarrow')

# 2. 전처리: pandas API 그대로 사용
df = df.dropna().query('age > 18')
df['log_income'] = np.log(df['income'].to_numpy() + 1)

# 3. ML 입력: NumPy 변환
X = df[feature_cols].to_numpy(dtype=np.float32)
y = df['target'].to_numpy()

model.fit(X, y)

.to_numpy() 호출 시 Arrow - NumPy 복사가 발생하나, 학습 단계는 한 번만 실행되므로 허용 가능.

pandas 3.0

3.0 부터 pyarrow 가 기본 백킹 이 될 예정 (논의 중). 지금부터 적응하면 좋다.

관련 위키

이 글의 용어 (5개)
[Pandas] 성능 / 메모리 최적화pandas
정의 pandas 의 흔한 성능 함정과 최적화 패턴. 벡터화 + dtype 선택 + 알고리즘 의 조합이 핵심. 사용 상황 | 상황 | 권장 접근 | |:---|:---| | 단순…
[Pandas] DataFramepandas
정의 은 2차원 레이블 테이블. 각 열이 , 모든 열이 같은 (행 라벨) 를 공유. SQL 테이블 / Excel 시트 / R data.frame 의 Python 대응체. 구조 시…
[Pandas] Nullable Types (Int64, boolean, string[pyarrow])pandas
정의 Nullable dtypes 는 NaN/None 을 타입 그대로 표현할 수 있는 pandas 의 새 타입 시스템. NumPy 기반의 (NaN 미허용) 의 한계를 극복. - …
[Pandas] read_csv / to_csvpandas
정의 는 CSV(Comma-Separated Values) 또는 구분자 기반 텍스트 파일을 DataFrame 으로 읽는 함수. pandas 사용의 출발점. 반대 방향은 : Dat…
[Pandas] read_parquet / to_parquetpandas
정의 Parquet 은 column-oriented binary 포맷. CSV 대비 수십 배 빠르고 작다. dtype 보존, 압축, 부분 컬럼 읽기 지원. 데이터 분석의 사실상 …

💬 댓글

사이트 검색 / 명령어

검색

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