python の pickle って嬉しいの?

python には pickle という、オブジェクトをシリアライズして保存しておくことができるモジュールが存在する。

例えば、ファイルからデータを読み込んで、pythonのオブジェクトへ変換する、という作業を色んな所で何度も繰り返す場合、 そのたびに生成することになるので、一定のコストがかかる。

これを一度オブジェクトへ変換したらそのオブジェクトをシリアライズして保存することで、2回目以降の生成コストを下げようというもの。 デシリアライズするので、コストがゼロになるわけではない、またシリアライズするためのコストもある。

同じデータを2回使うくらいであれば、シリアライズ、デシリアライズするコストとオブジェクトへ変換するコストを比べるとあまり意味がないかもしれない。

サンプルとして、下記のような100万行程度のcsvを作成し、テストする。

import random

with open("test.csv","w+") as f:
    for i in range(1000000):
        v = [str(random.randrange(10)) for x in range(10)]
        f.write(",".join(v) + "\n")

読み込みのコードは下記のようなもの。何も出力しないと寂しいので一応columnsを出力している。

import pandas

df = pandas.read_csv('test.csv')
print(df.columns)

pickleを利用してシリアライズするコードは下記。

import pandas
import pickle

with open("test.pickle","wb+") as f:
    df = pandas.read_csv('test.csv')
    pickle.dump(df,f)

pickleを利用してデシリアライズするコードは下記。

import pandas
import pickle

with open("test.pickle","rb") as f:
    df = pickle.load(f)
    print(df.columns)

計測は単に

$ time python code.py

で行い、user 時間を測る。

計測結果

csv読み込み

user 0m1.012s, 0m1.045s, 0m1.053s, 0m0.970s

csv読み込み + シリアライズ

user 0m1.091s, 0m1.087s, 0m1.139s, 0m1.206s

シリアライズ

user 0m0.491s, 0m0.495s, 0m0.487s, 0m0.482s

ざっくり、csvをdataframeにするのに1.0sec シリアライズに 0.1-0.2sec、デシリアライズに 0.5sec くらいかかっていることがわかる。

これなら2度読み込む場合でも読み込んだらpickleでシリアライズしておいたほうが良いかも

ただし、シリアライズしてファイルに書き出すと、サイズがざっくり4倍くらいになるので、データサイズが膨大な場合はディスク容量に注意。 IOリードが心配になることもあるのかな?