Python: Parquetフォーマットファイルを入出力する (Pandasとpyarrow)
今回はテーブルデータをParquetファイルで扱う方法について2つ紹介します。
コードは以下の環境で動作確認してます。
% python --version Python 3.8.5 % pip list Package Version --------------- ------- numpy 1.19.1 pandas 1.1.0 pip 20.2 pyarrow 1.0.0 python-dateutil 2.8.1 pytz 2020.1 setuptools 49.2.0 six 1.15.0
Apache Parquet
Apache Parquet1はApacheプロジェクトの1つで、環境に依存しない列指向のファイルフォーマットを定義・メンテナンスしています。
Parquetは以下の特徴を持ちます。詳細は https://parquet.apache.org/documentation/latest/ を参照ください。
- 列指向フォーマットのため、行指向と比較して、圧縮効率や列に対する集計処理などにおいてアドバンテージを持つ
- Google Researchが2010年に発表した Dremel: Interactive Analysis of Web-Scale Datasets のアルゴリズムを実装
- プログラミング言語、CPUアーキテクチャ等に非依存のため、利用できるプラットフォームが豊富
- Google BigQueryやAmazon AthenaなどもデータソースフォーマットとしてParquetを選択可能
- ネストしたカラムもエンコード可能
サポートされるデータ型
Parquetで利用できるデータ型だけ確認しておきます。文字列はBYTE_ARRAYに変換する必要があります。
- BOOLEAN: 1 bit boolean
- INT32: 32 bit signed ints
- INT64: 64 bit signed ints
- INT96: 96 bit signed ints
- FLOAT: IEEE 32-bit floating point values
- DOUBLE: IEEE 64-bit floating point values
- BYTE_ARRAY: arbitrarily long byte arrays.
Pandas DataFrameを用いたParquetファイルの変換
Pandas DataFrameではParquetのファイルを入出力するためのメソッドとして、to_parquetとread_parquetが実装されています。
DataFrameをParqueに保存・ロードする簡単な例を示します。文字列や日付型、NaNを含むデータも難なく変換できてます。
import pandas as pd from datetime import datetime dt = datetime.now() df = pd.DataFrame({ "id": [1, 2, 3], "name": ["Tanaka", "Suzuki", "Sato"], "rating": [3.5, None, 4.2], "created_at": [dt, dt, dt], }) print(df.info()) # <class 'pandas.core.frame.DataFrame'> # RangeIndex: 3 entries, 0 to 2 # Data columns (total 4 columns): # # Column Non-Null Count Dtype # --- ------ -------------- ----- # 0 id 3 non-null int64 # 1 name 3 non-null object # 2 rating 2 non-null float64 # 3 created_at 3 non-null datetime64[ns] # dtypes: datetime64[ns](1), float64(1), int64(1), object(1) # memory usage: 224.0+ bytes # Parquetで保存 df.to_parquet("./df.parquet") # Parquetからロード loaded_df = pd.read_parquet("./df.parquet") print(loaded_df.info()) # <class 'pandas.core.frame.DataFrame'> # RangeIndex: 3 entries, 0 to 2 # Data columns (total 4 columns): # # Column Non-Null Count Dtype # --- ------ -------------- ----- # 0 id 3 non-null int64 # 1 name 3 non-null object # 2 rating 2 non-null float64 # 3 created_at 3 non-null datetime64[ns] # dtypes: datetime64[ns](1), float64(1), int64(1), object(1) # memory usage: 224.0+ bytes print(loaded_df) # id name rating created_at # 0 1 Tanaka 3.5 2020-08-15 13:33:42.224807 # 1 2 Suzuki NaN 2020-08-15 13:33:42.224807 # 2 3 Sato 4.2 2020-08-15 13:33:42.224807
Apache Arrow
Apache ArrowもApacheプロジェクトの1つです。こちらはインメモリの列指向データフォーマットを定義し、ライブラリとして提供してます。
Arrowの特徴はこちらです。詳細は https://arrow.apache.org/overview/ を参照ください。
- 同じ列は同じメモリブロックに含まれるようにレイアウトする
- SIMD (Single Instruction, Multiple Data) アーキテクチャのCPUで高速に入出力できる
- プログラミング言語に依存しないフォーマットで、ネストしたデータ型やユーザ定義の型などもサポート
- Arrowを共通のストレージ (= ハブ) とし、Arrowとのシリアライザ・デシリアライザを実装するだけで、他のプログラミング言語やデータソースとのデータのやり取りができる
pyarrowを用いたParquetファイルの変換
このArrowのPython実装ライブラリの1つがpyarrowです。各種ファイルフォーマットやDataFrameなどに対応しており、例えば、CSVからParquet、ParquetからDataFrameといった変換もpyarrowを仲介することで可能となります。
pip install pyarrow
でインストールできます- 内部的にはpyarrow.Tableオブジェクトとして扱われます
CSVファイル -> Arrowテーブル -> Parquetファイル -> Arrowテーブル -> DataFrameオブジェクト という変換を行います。
# 上の続き import pyarrow import pyarrow.parquet import pyarrow.csv df.to_csv("test.csv", index=False) # CSVファイルをArrow形式でロード loaded_table = pyarrow.csv.read_csv("./test.csv") print(loaded_table) # pyarrow.Table # id: int64 # name: string # rating: double # created_at: string # Parquetに変換して保存 pyarrow.parquet.write_table(loaded_table, "./test.parquet") # ParquetファイルをArrow形式でロード loaded_parquet = pyarrow.parquet.read_table("./test.parquet") print(loaded_parquet) # pyarrow.Table # id: int64 # name: string # rating: double # created_at: string # ArrowをDataFrameへ変換 loaded_df = loaded_parquet.to_pandas() print(loaded_df) # id name rating created_at # 0 1 Tanaka 3.5 2020-08-15 14:15:08.543007 # 1 2 Suzuki NaN 2020-08-15 14:15:08.543007 # 2 3 Sato 4.2 2020-08-15 14:15:08.543007
まとめ
今回はParquetファイルをPythonで入出力するための方法を2つ紹介しました。
-
/ˈpɑːki,ˈpɑːkeɪ/ (パーキ、パーケイ) と読むそうです。↩