pandas.DataFrame, Seriesをpickleで保存、読み込み(to_pickle, read_pickle) | note.nkmk.me

pandas.DataFrame, Seriesをpickleで保存、読み込み(to_pickle, read_pickle)

Posted: | Tags: Python, pandas

pandas.DataFrame, pandas.Seriesオブジェクトをそのままpickleファイルとして保存するにはto_pickle()メソッド、保存したpickleファイルを読み込むにはpd.read_pickle()関数を使う。

ここでは以下の内容について説明する。

  • pickleとは
  • pandasでpickleを使う利点
    • CSVファイルで保存・読み込みする場合
    • pickleファイルで保存・読み込みする場合
  • 圧縮処理

pickleとは

pickleはPython標準ライブラリに含まれているモジュールで、Pythonオブジェクトをバイト列に変換(シリアライズ、pickle化)したり、バイト列からPythonオブジェクトに変換(デシリアライズ、非pickle化)したりするために使われる。

便宜上、ここではpickle化されて保存されたファイルをpickleファイルと呼ぶこととする。

なお、上記pickleモジュールのドキュメントにあるように出所不明なpickleファイルは危険な可能性があるので注意。

警告 pickle モジュールはエラーや不正に生成されたデータに対して安全ではありません。信頼できない、あるいは認証されていないソースから受け取ったデータを非 pickle 化してはいけません。
12.1. pickle --- Python オブジェクトの直列化 — Python 3.6.6 ドキュメント

pandasでpickleを使う利点

pandasではpandas.DataFrame, pandas.SeriesオブジェクトをCSVファイルやJSONファイルなどの形式で保存したり読み込んだりするメソッドが用意されている。

pickleファイルはCSVファイルやJSONファイルなどと異なりエディタで中身を確認したり他のアプリケーションで使い回すことはできないが、保存時・読み込み時に特別な設定や処理をすることなくオブジェクトをそのまま読み書きできるという利点がある。

以下のpandas.DataFrameを例とする。日時情報をインデックスとする時系列データで、'list'列にはlist型オブジェクトが格納されている。

import pandas as pd

df = pd.DataFrame({'list': [[0, 0], [0, 1], [1, 0], [1, 1]]},
                  index=pd.date_range('2018-01-01', '2018-01-04', freq='D'))

print(df)
#               list
# 2018-01-01  [0, 0]
# 2018-01-02  [0, 1]
# 2018-01-03  [1, 0]
# 2018-01-04  [1, 1]

print(df.index)
# DatetimeIndex(['2018-01-01', '2018-01-02', '2018-01-03', '2018-01-04'], dtype='datetime64[ns]', freq='D')

print(type(df['list'][0]))
# <class 'list'>

CSVファイルで保存・読み込みする場合

CSVで保存して再度読み込む場合、まず、時系列データとしてインデックスを指定するためにread_csv()の引数index_colparse_datesを指定する必要がある。

df.to_csv('data/dst/pandas_obj.csv')

df_from_csv = pd.read_csv('data/dst/pandas_obj.csv', index_col=0, parse_dates=True)

print(df_from_csv)
#               list
# 2018-01-01  [0, 0]
# 2018-01-02  [0, 1]
# 2018-01-03  [1, 0]
# 2018-01-04  [1, 1]

print(df_from_csv.index)
# DatetimeIndex(['2018-01-01', '2018-01-02', '2018-01-03', '2018-01-04'], dtype='datetime64[ns]', freq=None)

さらに、'list'列は文字列として読み込まれるので、例えば組み込み関数eval()を各要素に適用してlist型オブジェクトに変換する必要がある。

print(type(df_from_csv['list'][0]))
# <class 'str'>

df_from_csv['list'] = df_from_csv['list'].apply(eval)

print(df_from_csv)
#               list
# 2018-01-01  [0, 0]
# 2018-01-02  [0, 1]
# 2018-01-03  [1, 0]
# 2018-01-04  [1, 1]

print(type(df_from_csv['list'][0]))
# <class 'list'>

pickleファイルで保存・読み込みする場合

to_pickle(), read_pickle()を使ってpickleファイルとして扱う場合、引数の指定や変換処理をする必要なくオブジェクトを保存でき、そのままの状態で復元できる。

df.to_pickle('data/dst/pandas_obj.pkl')

df_from_pkl = pd.read_pickle('data/dst/pandas_obj.pkl')

print(df_from_pkl)
#               list
# 2018-01-01  [0, 0]
# 2018-01-02  [0, 1]
# 2018-01-03  [1, 0]
# 2018-01-04  [1, 1]

print(df_from_pkl.index)
# DatetimeIndex(['2018-01-01', '2018-01-02', '2018-01-03', '2018-01-04'], dtype='datetime64[ns]', freq='D')

print(type(df_from_pkl['list'][0]))
# <class 'list'>

作業を一時中断するためにオブジェクトの状態を保存しておきたい場合などにも、特に何も考える必要がないpickleファイルは便利。

さらに、CSVなどに比べて処理速度が速いというメリットもある。

圧縮処理

拡張子を.gz, .bz2, .xz, .zipとして指定すると、自動で圧縮・解凍処理が行われる。

df.to_pickle('data/dst/pandas_obj.zip')

df_from_pkl_zip = pd.read_pickle('data/dst/pandas_obj.zip')

print(df_from_pkl_zip)
#               list
# 2018-01-01  [0, 0]
# 2018-01-02  [0, 1]
# 2018-01-03  [1, 0]
# 2018-01-04  [1, 1]

引数compressionに明示的に形式('gzip', 'bz2', 'xz', 'zip')を指定することも可能。

関連カテゴリー

関連記事