Closed1

Pandasでparquetに書き出す際に全行がNullだと型情報がなくなることがある

ギンギツネさんギンギツネさん

ざっくりこんな話

PandasのDataFrameをparquetに保存する際に、特定の列の全行Null値の場合はparquet内でのデータ型がnullになってしまう。

(作成済みのDBへparquetをインポートする際にこういうことがあると型が変換できないとエラーが出て困ることがある)

検証DataFrame

こういったDataFrameを3分割してparquetに吐き出す。

In [1]: import pandas as pd

In [2]: import pyarrow as pa

In [3]: df = pd.Series(["2024-01-01", None, "2024-01-02", None, "2024-01-03", "2024-01-04", None, None, None]).astype("datetime64[us]").dt.date.to_frame()

In [4]: df
Out[4]: 
            0
0  2024-01-01 ┐
1         NaT ├─ 0.parquetに吐き出す (date32[Day]型になる)
2  2024-01-02 ┘
3         NaT ┐
4  2024-01-03 ├─ 1.parquetに吐き出す (date32[Day]型になる)
5  2024-01-04 ┘
6         NaT ┐
7         NaT ├─ 2.parquetに吐き出す (null型になる)
8         NaT ┘

正常ケース: parquet内のデータ型がdate32型になる

In [5]: df.iloc[0:3].to_parquet("/tmp/0.parquet")

In [6]: pa.parquet.read_table("/tmp/0.parquet")
Out[6]: 
pyarrow.Table
0: date32[day]
----
0: [[2024-01-01,null,2024-01-02]]
In [7]: df.iloc[3:6].to_parquet("/tmp/1.parquet")

In [8]: pa.parquet.read_table("/tmp/1.parquet")
Out[8]: 
pyarrow.Table
0: date32[day]
----
0: [[null,2024-01-03,2024-01-04]]

異常ケース: 全行NULL値だとparquetのデータ型がNULLになる

In [9]: df.iloc[6:9].to_parquet("/tmp/2.parquet")

In [10]: pa.parquet.read_table("/tmp/2.parquet")
Out[10]: 
pyarrow.Table
0: null
----
0: [3 nulls]

対策

(pandasだけではどうにもならないのでpyarrowで直接キャストした)

In [11]: pa.parquet.write_table(
    ...:     pa.Table.from_pandas(
    ...:         df.iloc[6:9]
    ...:     ).cast(
    ...:         pa.schema([
    ...:             pa.field("0", pa.date32())
    ...:         ])
    ...:     ),
    ...:     "/tmp/2.parquet"
    ...: )

In [12]: pa.parquet.read_table("/tmp/2.parquet")
Out[12]: 
pyarrow.Table
0: date32[day]
----
0: [[null,null,null]]
このスクラップは2024/02/09にクローズされました