Pandas나 PySpark등을 사용하다보면 *.csv
포맷으로는 만족하지 못하는 경우가 많다.
예를들어..
Data Type이 저장되지 않는다.
너무 많은 데이터는 저장해도 CSV의 이점(엑셀로 열어볼 수 있다)을 살리지 못한다.
특정 Column만 선택하는 것이 불가능하다. (= 전체 파일을 항상 모두 열어야 한다)
용량이 상대적으로 작지만 크다 (압축을 하지 않은 경우)
(종종) Escaping이 잘 되지 않은 경우에는 파일 Parsing이 깨진다.
한글이 들어간 csv의 경우 “MS Excel”에서는 BOM이 없으면 UTF-8을 제대로 인식하지 못한다. (한편, euc-kr 인코딩은 잘 읽는다.)
등등.. 여러가지 이슈가 있다.
그렇다면, 어떤 형식을 써야 할까?
그럼 어떤 포맷을 써야 하나?
원본 데이터를 곧바로 가져다 사용하는 경우(= Athena, RedShift, BigQuery, DB 등이 데이터소스가 아닌 경우)에는 보통 csv
, json
, parquet
이 세가지 형식이 가장 범용적이다.
그 중에서도 특히 csv와 json을 자주 사용한다.
작은 데이터의 경우 csv를, API에서는 json을 제공하는 경우가 많다.
위에서 볼 수 있듯 파일 형식에 따라 표현할 수 있는 방식이 다르다.
하지만 결론은 대부분 “Parquet 파일을 써라!” 인 경우가 많다.
Snappy 압축으로 Parquet 파일 사용하기
Parquet형식은 Pandas에서 기본 옵션으로 Snappy
압축을 사용한다.
Snappy 압축은 google에서 개발한 ‘적당히 빠르고 적당히 압축 잘되는’ 라이브러리이고, 대용량의 데이터를 ‘빠르게 읽고 쓰는데 적합한, 하지만 용량 축소는 잘 되는’ 아주 멋진 압축 방식이다.
한편, 기본 옵션인 Snappy 압축을 이용해 parquet파일을 쓰기 위해 새로운 DataFrame을 만들어 저장하려고 해도 보통의 경우 에러에 부딛힌다.
아래와 같은 간단한 코드를 실행한다고 가정해 보자.
1 | import pandas as pd |
Docker로 continuumio/anaconda3:2019.10
에서 ipython 쉘에서 실행시 아래와 같은 에러가 발생한다. 아래 에러는 Parquet 파일을 사용하기 위해서는 pyarrow
혹은 fastparquet
패키지가 필요하다는 경고다.
아래 명령어를 통해 fastparquet
패키지를 설치해주자.
1 | pip install fastparquet |
한편, 위 명령어를 입력하면 상황에 따라 다르지만 아래와 같은 에러가 발생한다.
위 에러는 gcc
명령어를 사용할 수 없어서 생긴 문제로, 아래 명령어로 빌드 관련 패키지를 설치하면 문제를 해결할 수 있다.
1 | apt update && apt install -y build-essential |
이제 다시 df.to_parquet()
를 실행하면 아래와 같이 정상적으로 설치가 되는 것을 볼 수 있다.
혹시
libsnappy
파일 관련해 에러가 발생하고 설치가 실패할 경우 아래 명령어로libsnappy-dev
를 설치해준 뒤fastparquet
설치를 다시 시도하면 성공한다.
1 apt update && apt install -y libsnappy-dev
Gzip 압축으로 Parquet 파일 사용하기
Snappy 압축이 좋기는 하지만 위와 같이 빌드 관련한 의존 패키지도 설치해야하고(꽤 무겁다), 때로는 의존성 라이브러리도 이슈가 종종 있어 사용하기 까다로운 측면이 있다.
따라서 시스템에서 보통 기본적으로 잘 지원하는 gzip
형식을 이용하기도 한다.
압축률은 gzip > snappy이며, 압축 속도는 gzip < snappy로 약간의 차이는 있다.
이때는 별다른 설치 없이 DataFrame 저장시에 compression
옵션만 제공하면 된다.
1 | import pandas as pd |
아래와 같이 아무런 에러도 없이 한번에 저장이 잘 되는 것을 볼 수 있다.
데이터 읽기
한편, 어떤 압축 방식(Gzip/Snappy/Uncompressed)을 사용하든 파일을 읽는 방식은 동일하다.
이때는 압축 방식을 알아서 유추해서 풀기 때문에 별도의 옵션을 주지 않아도 된다.
1 | df = pd.read_parquet('sample.parquet') |
또한, 특정 컬럼만 읽으려고 한다면 아래와 같이 columns
인자를 전달하면 파일 전체 대신 해당 컬럼만 읽어서 DataFrame을 생성한다.
1 | df = pd.read_parquet('sample.parquet', columns=['a', 'b']) |