메뉴 닫기

파이썬 Parquet 저장과 불러오기 완전 정복, pandas to_parquet와 read_parquet에서 pyarrow와 fastparquet 그리고 nullable dtype까지

파이썬 Parquet 저장과 불러오기 완전 정복, pandas to_parquet와 read_parquet에서 pyarrow와 fastparquet 그리고 nullable dtype까지

📌 판다스 DataFrame을 Parquet으로 안전하게 기록하고 다시 읽을 때 dtype까지 깔끔하게 지키는 방법을 정리합니다

데이터 다룰 때 한 번쯤은 이런 경험이 있을 거예요.
CSV로 저장했다가 다시 불러오니까 숫자 컬럼이 전부 문자열이 돼 있다든지, 결측치(None, NaN) 때문에 int가 갑자기 float로 바뀐다든지 하는 상황 말이죠.
특히 운영 테이블이나 로그 데이터를 주기적으로 적재할 때는 이런 타입 깨짐이 쌓이면 나중에 조인이나 분석 로직이 미세하게 틀어지기도 합니다.
그 때문에 많은 팀이 파이썬에서 Parquet을 기본 저장 포맷처럼 쓰고 있고, 실제로 pandas의 to_parquet / read_parquet 같은 I/O 함수로 하루에도 수십 번씩 데이터를 읽고 쓰게 됩니다.
Parquet은 컬럼 단위로 압축되고 타입 정보를 그대로 담을 수 있어서 대용량 데이터에도 유리하고, Spark나 DuckDB 같은 다른 엔진과도 자연스럽게 공유할 수 있다는 점이 계속 사랑받는 이유예요.

여기서 많이 헷갈리는 부분이 딱 세 가지입니다.
첫째, pandas에서 Parquet을 쓸 때 어느 엔진을 써야 하는가, 즉 pyarrow.parquet 기반으로 갈지 아니면 fastparquet으로 갈지.
둘째, DataFrame을 파일로 저장할 때 to_parquet이 실제로 어떤 옵션을 지원하고 어떤 식으로 인덱스나 압축을 다루는지.
그리고 셋째, 다시 read_parquet으로 읽어올 때 nullable dtype을 어떻게 보존할 수 있는지예요.
nullable dtype은 pandas에서 결측값을 깔끔하게 다룰 수 있도록 만들어진 정수형(Int64처럼 대문자 I), boolean, string 전용 타입 계열이라서, 컬럼 타입이 중간에 float나 object로 망가지는 걸 막아줍니다.
이 부분은 실제 파이프라인 안정성과 직결되기 때문에, 현업에서도 꽤 민감하게 관리합니다.

이 글에서는 파이썬에서 쓰는 대표적인 Parquet I/O 흐름을 기준으로 정리합니다.
pandas의 DataFrame.to_parquet()가 내부적으로 어떤 식으로 pyarrow나 fastparquet 엔진을 호출하는지, 압축 옵션과 파티셔닝 옵션은 어떤 의미인지, 인덱스 저장은 기본적으로 어떻게 처리되는지 등 실사용 관점으로 풀어볼 거예요.
또한 pandas.read_parquet()으로 다시 불러올 때 dtype이 바뀌어버리는 문제를 줄이는 방법, 즉 nullable dtype과 dtype_backend 개념처럼 최신 pandas에서 제공하는 타입 유지 전략도 함께 살펴봅니다.
실제로 어떤 선택을 하면 코드가 덜 깨지는지, 팀 규칙은 어떻게 잡는 게 좋은지까지 자연스럽게 감을 잡을 수 있을 거예요.



📌 파이썬에서 Parquet을 쓰는 이유와 장점

데이터를 파일로 저장한다고 하면 아직도 CSV부터 떠올리는 경우가 많지만, 실제로 대용량 분석이나 파이프라인 자동화를 돌리는 환경에서는 점점 Parquet이 기본값처럼 자리 잡았습니다.
Parquet은 컬럼 단위(columnar)로 저장되는 포맷이라서, 특정 컬럼 몇 개만 읽고 싶은 경우에도 그 부분만 효율적으로 가져올 수 있고, 불필요한 컬럼까지 전부 메모리에 올리지 않아도 됩니다.
이건 곧 I/O 속도와 메모리 사용량을 아낀다는 뜻이라서 로그 적재, 데이터 레이크 저장소, 대시보드 백엔드 쿼리처럼 반복 호출이 많은 작업일수록 체감 차이가 커집니다.

또 하나 중요한 점은 타입 정보가 그대로 박제된다는 것입니다.
CSV는 결국 전부 텍스트라서 다시 읽을 때 숫자도 문자열이 될 수 있고, 0/1 컬럼이 bool인지 int인지 애매한 경우가 많죠.
반면 Parquet은 각 컬럼이 어떤 타입인지 메타데이터에 담아둡니다.
pandas에서 to_parquet()으로 DataFrame을 저장하면, 정수형이면 정수형, boolean이면 boolean처럼 해당 dtype 자체가 Arrow 스키마나 fastparquet 메타데이터에 함께 기록됩니다.
그래서 동일한 스키마를 여러 번 주고받는 파이프라인(ETL, 배치 적재, Spark ↔ Python 연동 등)에서 컬럼별 의미가 덜 흔들립니다.

pandas의 DataFrame.to_parquet()은 기본적으로 engine=’auto’ 상태인데, 이 값은 내부적으로 먼저 pyarrow를 시도하고 pyarrow가 설치돼 있지 않으면 fastparquet으로 자동 폴백하는 구조입니다.
즉, 별도 코드를 바꾸지 않아도 pyarrow.parquet과 fastparquet 중 가용한 엔진을 알아서 잡아준다는 뜻이에요.
이 덕분에 팀마다 환경이 조금씩 달라도(어디는 Spark/Arrow 기반, 어디는 경량 파이썬 only) 큰 수정 없이 같은 코드로 Parquet을 쓸 수 있다는 게 실무에서 정말 편합니다.

Parquet의 또 다른 장점은 압축 방식 선택의 자유예요.
to_parquet()은 압축 알고리즘을 기본적으로 ‘snappy’로 지정하지만, 필요하면 gzip, brotli, lz4, zstd 등으로 바꿀 수 있습니다.
CPU와 디스크 비용의 균형을 보고 선택할 수 있다는 점이 좋아요.
예를 들어 장기 보관 데이터 레이크라면 zstd나 gzip처럼 더 높은 압축률을 선호할 수 있고, 반대로 대화형 분석(바로 열어서 살펴보는 용도)이라면 snappy나 lz4처럼 빠른 해제를 쓰는 경우가 많습니다.

또 한 가지 많이 쓰는 기능이 partition_cols입니다.
to_parquet() 호출 시 특정 컬럼을 partition_cols로 넘기면, 실제로는 한 개의 거대한 파일이 아니라 디렉터리 트리 형태로 나뉘어 저장돼요.
예를 들어 날짜(date=2025-10-29), 지역(country=KR) 이런 식으로 디렉터리 단위로 쪼개 둘 수 있어서, 나중에 read_parquet()으로 다시 읽을 때 특정 파티션만 빠르게 로딩할 수 있습니다.
데이터 레이크(S3, GCS 등)에서 흔히 보는 year=2025/month=10/day=29 폴더 구조가 바로 이 패턴이에요.

마지막으로 타입 안정성 관점에서 꼭 짚고 싶은 게 nullable dtype입니다.
pandas에는 Int64 (대문자 I), boolean, string 같은 확장 dtype이 있고, 이 타입들은 결측값 <NA>를 자연스럽게 포함할 수 있게 설계되어 있습니다.
이게 왜 중요하냐면, 기존 NumPy 기반 int 컬럼은 NaN을 담을 수 없어서 한 번이라도 결측이 생기면 float64로 바뀌어버리곤 했거든요.
nullable dtype은 그 문제를 근본적으로 줄여주고, pyarrow 같은 최신 Parquet 엔진이 이 정보를 점점 더 잘 보존해주도록 업데이트되고 있습니다.
즉 Parquet은 단순히 “용량 줄이기 좋은 컬럼 포맷”이 아니라 “원래 갖고 있던 데이터 의미를 손상 없이 들고 다닐 수 있게 도와주는 교환 포맷”에 가깝습니다.

  • 📦Parquet은 컬럼 단위 포맷이라 필요한 컬럼만 빨리 읽을 수 있어요.
  • 🗂️pandas to_parquet()은 pyarrow 또는 fastparquet 엔진을 자동으로 선택할 수 있어요.
  • 🧵압축 방식은 snappy, gzip, brotli, lz4, zstd 등으로 골라 저장 가능합니다.
  • 🪪nullable dtype(Int64, boolean, string 등)은 결측값 <NA>를 허용하면서 타입을 유지해 줍니다.
  • 🧭partition_cols로 저장하면 날짜/지역 등으로 자동 디렉터리 파티셔닝되어 대규모 적재에도 관리가 쉬워집니다.

💡 TIP: 반복 분석용 로그나 지표 테이블이라면 애초에 CSV 대신 Parquet으로 적재해 두는 게 훨씬 편합니다.
CSV는 일단 불러온 다음 스키마 정리 작업을 또 해야 하지만, Parquet은 read_parquet() 한 줄로 바로 DataFrame이 복원되고 타입 안정성까지 어느 정도 따라오기 때문입니다.

📌 pandas to_parquet과 pyarrow.parquet 동작 방식

pandas에서 Parquet 파일을 저장할 때 가장 많이 쓰이는 함수가 DataFrame.to_parquet()입니다.
이 함수는 내부적으로 지정된 engine을 불러와 데이터를 변환하고 파일에 기록합니다.
보통 아무 옵션을 주지 않으면 pandas는 pyarrow 엔진을 우선 사용하고, 설치되어 있지 않다면 자동으로 fastparquet으로 전환합니다.
즉, 코드 한 줄로 Arrow 기반 I/O와 fastparquet 기반 I/O를 자유롭게 쓸 수 있는 구조죠.

pyarrow는 Apache Arrow 프로젝트의 일부로, DataFrame을 Arrow 테이블 형태로 변환한 다음 그 테이블을 pyarrow.parquet.write_table() 함수를 통해 저장합니다.
이 과정에서 pandas의 index를 포함할지 여부(index 옵션), 압축 알고리즘(compression), 파티셔닝(partition_cols) 등 세부 설정을 그대로 전달합니다.
예를 들어 다음과 같은 코드로 사용할 수 있습니다.

CODE BLOCK
import pandas as pd

# 샘플 데이터 생성
df = pd.DataFrame({
    "id": [1, 2, 3],
    "score": [95.5, 82.0, 77.5],
    "passed": [True, True, False]
})

# pyarrow 엔진으로 Parquet 저장
df.to_parquet("scores.parquet", engine="pyarrow", compression="snappy", index=False)

이렇게 저장된 파일은 Parquet 메타데이터에 컬럼 이름, 데이터 타입, null 허용 여부, 압축 방식 등이 함께 기록됩니다.
덕분에 다른 언어(R, Java, Spark 등)로 불러와도 동일한 스키마를 유지할 수 있습니다.
pyarrow는 특히 nullable dtype을 잘 보존하는 편이며, pandas 2.0 이후부터는 Arrow 데이터 타입으로 내부 변환이 한층 자연스러워졌습니다.

🧱 pyarrow 엔진의 장점

pyarrow를 사용하는 가장 큰 이유는 정확성입니다.
Arrow는 데이터 타입 시스템이 pandas보다 정교하게 설계되어 있어서, int8, int16, int32, int64뿐 아니라 nullable 버전까지 세밀하게 매핑할 수 있습니다.
특히 pandas 2.1부터는 dtype_backend=”pyarrow” 옵션을 통해 read_parquet() 시점에도 Arrow 타입으로 바로 불러올 수 있습니다.
이 옵션을 사용하면 기존의 numpy 기반 dtype보다 메모리 사용량이 줄고, 결측값 처리가 안정적입니다.

예를 들어 다음과 같이 parquet 파일을 다시 읽을 수 있습니다.

CODE BLOCK
# Arrow 기반 dtype으로 불러오기
df2 = pd.read_parquet("scores.parquet", engine="pyarrow", dtype_backend="pyarrow")

print(df2.dtypes)

이렇게 하면 DataFrame의 각 컬럼이 Arrow 기반 dtype으로 로드되어, nullable intstring, boolean 컬럼이 원래 형태를 유지합니다.
이건 특히 대규모 ETL 파이프라인이나 ML 데이터셋을 전처리할 때, 한 번이라도 dtype이 바뀌면 다운스트림 코드가 깨지는 문제를 예방하는 데 매우 유용합니다.

⚙️ to_parquet 옵션 살펴보기

to_parquet() 함수는 단순히 파일 하나를 만드는 함수로 끝나지 않습니다.
데이터 저장 시 실제로 많이 사용하는 주요 옵션들을 정리하면 다음과 같습니다.

옵션명 설명
engine pyarrow 또는 fastparquet 선택 (기본: auto)
compression 압축 방식 선택 (snappy, gzip, zstd 등)
index 인덱스 저장 여부 (기본 True)
partition_cols 디렉터리 파티션 기준 컬럼 목록
storage_options S3, GCS 등 원격 저장소 설정 옵션

특히 index=False를 지정하면 DataFrame의 인덱스 컬럼을 별도 저장하지 않아도 되기 때문에, Spark 같은 외부 툴에서 Parquet 파일을 더 단순하게 읽을 수 있습니다.

💎 핵심 포인트:
pyarrow는 pandas의 nullable dtype을 가장 안정적으로 유지할 수 있는 엔진입니다.
특히 dtype_backend=”pyarrow” 옵션과 함께 쓰면 dtype 변형 없이 그대로 round-trip이 가능합니다.



📌 fastparquet 엔진 선택과 성능 포인트

pandas의 to_parquet()read_parquet() 함수는 pyarrow 외에도 fastparquet이라는 엔진을 지원합니다.
fastparquet은 Python에서 순수하게 구현된 Parquet I/O 라이브러리로, Arrow보다 설치가 가볍고 의존성이 적습니다.
특히 로컬 환경에서 빠르게 파일을 읽고 쓰거나, 단일 머신에서 간단한 배치 처리를 돌릴 때 속도 면에서 pyarrow보다 더 유리한 경우도 있습니다.

fastparquet은 Dask, Vaex, Polars 같은 다른 파이썬 데이터 프레임 프레임워크에서도 폭넓게 사용되고 있습니다.
기본적으로 Cython으로 컴파일된 경량 코드 기반이라서, 반복 I/O가 많은 시나리오에서도 안정적으로 동작합니다.
그리고 Arrow 기반보다 pandas의 내부 데이터 구조와 조금 더 유사하게 작동하기 때문에, pyarrow보다 직관적인 경우도 있습니다.

🚀 fastparquet의 주요 특징

fastparquet은 pyarrow와 같은 포맷의 Parquet 파일을 읽고 쓸 수 있습니다.
즉, 한쪽에서 pyarrow로 저장하고 다른 쪽에서 fastparquet으로 읽더라도 파일 호환이 유지됩니다.
그뿐만 아니라 fastparquet은 멀티 파일 쓰기를 지원해서, row_group_offsetsfile_scheme 옵션을 이용해 데이터를 여러 조각으로 나눠 병렬 저장할 수 있습니다.
이건 특히 Dask 클러스터나 다중 CPU 환경에서 매우 유용합니다.

예를 들어 다음 코드를 보면 fastparquet으로 데이터를 저장하고 읽는 기본적인 형태를 알 수 있습니다.

CODE BLOCK
import pandas as pd

df = pd.DataFrame({
    "city": ["Seoul", "Busan", "Incheon"],
    "population": [9700000, 3400000, 2900000]
})

# fastparquet으로 저장
df.to_parquet("korea_city.parquet", engine="fastparquet", compression="gzip")

# 다시 읽기
df2 = pd.read_parquet("korea_city.parquet", engine="fastparquet")
print(df2)

fastparquet은 압축 알고리즘으로 snappy, gzip, brotli 등을 지원합니다.
단, Arrow에 비해 압축 속도나 최신 코덱 대응성이 다소 제한될 수 있으므로, CPU 자원이 넉넉한 환경에서는 pyarrow가 더 안정적입니다.
반면 의존성 최소화간결한 배포가 중요할 때는 fastparquet이 적합합니다.

🧩 fastparquet vs pyarrow 비교

비교 항목 pyarrow fastparquet
의존성 C++ 기반, Arrow 필수 설치 Pure Python (Cython 가속), 의존성 적음
성능 대용량 처리에 유리 소규모 반복 I/O에 유리
nullable dtype 지원 완벽하게 지원 (Arrow 기반) 부분 지원 (object형으로 대체될 수 있음)
호환성 Spark, DuckDB 등과 완전 호환 일부 엔진에서 제한적

정리하자면, pyarrow는 대규모 데이터를 안정적으로 다루는 데 강점을 지니고 있고, fastparquet은 가벼운 프로젝트나 서버 없는 환경(예: Lambda, 로컬 파이썬 실행)에 더 적합합니다.
즉, 빠른 스타트업이나 개발 환경 배포 단순화가 중요하다면 fastparquet을, 데이터 일관성과 dtype 안정성이 핵심이라면 pyarrow를 선택하는 것이 이상적입니다.

💡 TIP: 팀 내 테스트용 데이터셋이나 로컬 캐시 파일을 빠르게 저장하고 싶다면 fastparquet으로 설정해 두세요.
설치가 간단하고, 로드 속도도 충분히 빠릅니다.

📌 nullable dtype과 결측값 처리 전략

데이터를 다루는 실무 환경에서 가장 흔한 문제 중 하나가 바로 결측값으로 인한 dtype 깨짐입니다.
pandas에서는 과거에 int 컬럼에 NaN이 생기면 자동으로 float64로 바뀌어버렸습니다.
이는 NaN이 부동소수(float) 타입이기 때문에 어쩔 수 없던 부분이었죠.
하지만 pandas 1.0 이후, 그리고 2.0대에 들어서는 이 문제를 근본적으로 해결하기 위해 nullable dtype 시스템이 도입되었습니다.

nullable dtype은 단순히 ‘결측값을 허용하는 데이터 타입’이 아닙니다.
내부적으로는 pandas._libs.missing.NAType을 이용해 결측을 관리하며, 기존의 np.nan과 달리 부정확한 타입 변환 없이 모든 dtype을 일관되게 유지합니다.
이 시스템은 정수(Int8~Int64), 부울(boolean), 문자열(string), 카테고리(category) 등의 데이터에 적용할 수 있습니다.

🔍 nullable dtype의 예시

예를 들어, 다음 코드에서처럼 일반 int 대신 Int64 dtype을 사용하면 결측값이 있어도 타입이 유지됩니다.
기존 float 변환 문제를 막는 핵심 포인트예요.

CODE BLOCK
import pandas as pd
import numpy as np

df = pd.DataFrame({
    "id": pd.Series([1, 2, np.nan], dtype="Int64"),
    "active": pd.Series([True, None, False], dtype="boolean"),
    "name": pd.Series(["홍길동", None, "이몽룡"], dtype="string")
})

print(df)
print(df.dtypes)

이 코드를 실행하면, NaN이 들어가도 int가 float으로 바뀌지 않고 Int64로 유지됩니다.
그리고 불리언과 문자열 컬럼도 각각 boolean, string dtype으로 남습니다.
즉, to_parquet()으로 저장할 때 이 dtype이 그대로 Arrow 스키마에 반영됩니다.

🧠 nullable dtype과 Parquet의 관계

Parquet 포맷은 컬럼 단위로 null mask(결측 여부)를 저장합니다.
즉, 어떤 행이 결측인지 비트맵 형태로 기록하기 때문에, pandas의 nullable dtype과 구조적으로 잘 맞습니다.
특히 pyarrow 엔진을 사용하면 DataFrame의 NA 상태가 그대로 Arrow Array로 직렬화되고, 다시 read_parquet() 시점에 복원됩니다.
반면 fastparquet의 경우, 아직 일부 nullable dtype을 완벽하게 지원하지 않아 boolean이나 string 타입이 object로 바뀔 수 있습니다.

이를 안정적으로 다루려면 pyarrow 엔진을 사용하면서, pandas의 최신 버전에서 제공하는 dtype_backend=”pyarrow” 옵션을 함께 사용하는 것이 좋습니다.
이 옵션은 내부적으로 nullable dtype과 Arrow 타입 간 매핑을 유지하여, 저장과 불러오기 과정에서 dtype이 달라지는 문제를 크게 줄여줍니다.

📌 nullable dtype을 안정적으로 관리하기 위한 팁

  • 💾데이터를 처음 만들 때부터 Int64, boolean, string dtype을 지정하세요.
  • 🧩가능하면 pyarrow 엔진을 사용하여 to_parquet / read_parquet 작업을 수행하세요.
  • 📘dtype_backend=”pyarrow” 옵션을 통해 dtype round-trip을 보장하세요.
  • ⚠️fastparquet은 nullable dtype 지원이 부분적이므로 dtype이 object로 바뀔 수 있습니다.

⚠️ 주의: CSV로 데이터를 저장할 때 nullable dtype은 그대로 유지되지 않습니다.
CSV는 타입 정보를 잃기 때문에, 반드시 Parquet을 사용해야 결측값을 포함한 dtype이 정확히 보존됩니다.



📌 read_parquet으로 다시 읽을 때 dtype 유지하는 법

Parquet 파일을 저장하는 것만큼 중요한 게 바로 다시 읽어올 때 dtype이 깨지지 않게 유지하는 것입니다.
많은 분들이 “파일은 잘 저장되는데 불러오면 int가 float으로 바뀐다”거나 “bool 컬럼이 object로 나온다”는 문제를 겪습니다.
이건 Parquet 포맷의 문제가 아니라, read_parquet()이 데이터를 복원할 때 어떤 엔진과 어떤 dtype 백엔드를 쓰느냐에 따라 달라집니다.

pandas의 read_parquet() 함수는 pyarrow와 fastparquet 두 엔진을 모두 지원합니다.
특히 pandas 2.1 이상부터는 dtype_backend 매개변수가 추가되어, 데이터를 불러올 때 dtype을 어떤 체계로 해석할지 명시적으로 지정할 수 있습니다.
이 덕분에 이전처럼 float 변환이나 object형 변환 없이 Arrow 기반 타입을 그대로 유지할 수 있게 되었죠.

📖 dtype_backend 옵션 이해하기

현재 pandas에서 사용할 수 있는 dtype_backend 옵션은 크게 두 가지입니다.

옵션명 설명
“numpy_nullable” nullable dtype(Int64, boolean 등)을 numpy 기반으로 유지
“pyarrow” Arrow 기반 dtype으로 직접 로드 (더 효율적이고 빠름)

이 옵션을 사용하면 Parquet을 읽는 순간부터 dtype이 고정되어, 결측값이 있어도 float 변환 없이 그대로 복원됩니다.
다음 예시를 보면 한눈에 이해될 거예요.

CODE BLOCK
import pandas as pd

# pyarrow 엔진으로 dtype_backend 지정
df = pd.read_parquet("scores.parquet", engine="pyarrow", dtype_backend="pyarrow")

print(df.dtypes)

위 코드를 실행하면 각 컬럼이 Arrow 전용 dtype으로 표시됩니다.
예를 들어 int 컬럼은 int64[pyarrow], 문자열은 string[pyarrow]로 나오죠.
이 타입들은 pandas 내부에서 바로 연산할 수 있고, 필요하면 다시 to_numpy()로 변환해도 문제 없습니다.

🧩 fastparquet으로 읽을 때 주의할 점

fastparquet 엔진도 read_parquet()에서 잘 작동하지만, 아직은 pyarrow만큼 nullable dtype을 완벽히 복원하지 못합니다.
일부 boolean, string 컬럼이 object dtype으로 로드되는 현상이 남아 있습니다.
이 문제를 피하려면 가능한 pyarrow 엔진을 사용하는 게 좋습니다.

만약 fastparquet을 꼭 써야 하는 환경이라면, read_parquet() 후에 dtype을 재정의하는 후처리를 추가해 두세요.
예를 들어 다음과 같은 간단한 변환 함수를 둘 수 있습니다.

CODE BLOCK
def restore_nullable(df):
    for col in df.select_dtypes(include="object").columns:
        if df[col].dropna().map(type).eq(bool).all():
            df[col] = df[col].astype("boolean")
        elif df[col].dropna().map(type).eq(str).all():
            df[col] = df[col].astype("string")
    return df

이 함수는 object 컬럼 중 boolean이나 string 값만 포함된 컬럼을 찾아, 다시 nullable dtype으로 변환합니다.
비록 임시방편이지만 fastparquet 기반 파이프라인에서도 dtype 정합성을 높이는 방법입니다.

💎 핵심 포인트:
read_parquet()에서는 반드시 dtype_backend 옵션을 지정하세요.
특히 pandas 2.1 이상이라면 dtype_backend=”pyarrow”로 설정해 두면 dtype 손상 없이 완전한 round-trip이 가능합니다.

자주 묻는 질문 (FAQ)

Parquet과 CSV의 가장 큰 차이는 무엇인가요?
CSV는 텍스트 기반 포맷으로 모든 데이터를 문자열로 저장하지만, Parquet은 컬럼 단위 바이너리 포맷이라 각 컬럼의 데이터 타입과 압축 정보를 함께 기록합니다.
따라서 Parquet은 용량이 훨씬 작고, 읽기 속도도 빠르며, dtype 정보까지 그대로 복원됩니다.
pyarrow와 fastparquet 중 어느 엔진을 써야 할까요?
대규모 데이터 처리, nullable dtype 안정성, Spark 연동 등을 고려한다면 pyarrow가 가장 좋습니다.
반면, 가볍고 빠르게 로컬 저장이나 테스트 데이터를 다룰 땐 fastparquet이 유리합니다.
Parquet 파일은 Excel로 열 수 있나요?
기본적으로 Excel은 Parquet을 직접 열 수 없습니다.
대신 pandas나 pyarrow로 CSV로 변환한 뒤 열거나, Microsoft Power BI, Tableau, DuckDB 같은 분석 도구를 이용하면 바로 읽을 수 있습니다.
Parquet에 저장된 데이터는 손상될 위험이 없나요?
Parquet은 압축과 인코딩 구조가 엄격히 정의된 바이너리 포맷이라 손상 확률이 낮습니다.
하지만 파일이 일부만 잘리거나 저장 중 중단되면 일부 row group이 깨질 수 있으므로, 저장 후 pyarrow.parquet.read_table()로 검증하는 게 좋습니다.
pandas에서 nullable dtype을 쓰면 성능이 느려지나요?
약간의 오버헤드는 있지만, pyarrow backend를 쓰면 거의 차이가 없습니다.
특히 dtype_backend=”pyarrow” 옵션을 쓰면 Arrow 메모리 포맷으로 효율적으로 관리됩니다.
partition_cols 옵션은 언제 사용하나요?
대용량 데이터를 날짜나 지역 같은 기준으로 나누어 저장할 때 사용합니다.
예를 들어 to_parquet(“data/”, partition_cols=[“date”])로 저장하면 date별로 폴더가 나뉘어 관리됩니다.
pyarrow와 fastparquet으로 만든 파일은 서로 호환되나요?
네, 두 엔진 모두 Parquet 표준 스펙을 따르기 때문에 파일 호환이 가능합니다.
다만 일부 dtype(특히 nullable boolean, string)은 fastparquet에서 완전히 동일하게 복원되지 않을 수 있습니다.
read_parquet으로 읽은 후 dtype이 바뀌는 걸 막으려면?
pandas 2.1 이상에서 dtype_backend=”pyarrow”로 지정하면 됩니다.
이 설정을 쓰면 int, boolean, string 컬럼 모두 Arrow 기반 nullable dtype으로 유지됩니다.

📌 파이썬 Parquet I/O와 dtype 관리의 핵심 요약

Parquet은 단순한 파일 포맷이 아니라, 데이터 품질을 유지하는 도구라고 해도 과언이 아닙니다.
pandas에서 to_parquet()read_parquet()을 잘만 사용하면, dtype 깨짐이나 결측 처리 문제 없이 안정적인 파이프라인을 만들 수 있습니다.
핵심은 pyarrow 엔진을 기본으로 두고, nullable dtypedtype_backend 옵션을 적극적으로 활용하는 것입니다.

만약 fastparquet을 선택해야 하는 상황이라면, object 타입으로 변환된 컬럼을 후처리해주는 함수(restore_nullable 등)를 함께 쓰는 것이 좋습니다.
또한 데이터를 저장할 때 index=False, compression 등의 옵션을 명확히 지정하면, 재사용성과 이식성이 높아집니다.
데이터 레이크나 분석 파이프라인에서 Parquet을 표준 포맷으로 쓰는 이유가 바로 이런 일관성과 효율성 때문입니다.

요약하자면 다음과 같습니다:

  • 📁Parquet은 컬럼 기반 저장으로 빠르고 압축 효율이 높습니다.
  • 🧱pyarrow는 dtype 안정성과 호환성이 우수해 대부분의 프로젝트에서 기본 엔진으로 권장됩니다.
  • fastparquet은 가볍고 설치가 쉬워 로컬 테스트나 간단한 파이프라인에 적합합니다.
  • 🧩nullable dtype(Int64, boolean, string 등)을 적극 활용하면 NaN으로 인한 float 변환 문제를 해결할 수 있습니다.
  • 🔍read_parquet() 시 dtype_backend=”pyarrow”로 지정하면 dtype round-trip이 완벽히 유지됩니다.

결국 Parquet은 “파일 형식”이 아니라, 데이터 품질을 자동으로 보존해주는 신뢰 가능한 교환 포맷으로 진화하고 있습니다.
데이터를 자주 주고받거나 장기 저장해야 하는 환경이라면, 이제는 Parquet을 기본 포맷으로 사용하는 게 표준이라고 할 수 있습니다.


🏷️ 관련 태그 :
Parquet, pyarrow, fastparquet, pandas, to_parquet, read_parquet, nullable dtype, 데이터직렬화, 데이터엔지니어링, PythonI/O