パンダを使用してデータフレームを保存する方法


317

現在CSV、スクリプトを実行するたびにかなり大きなデータフレームをインポートしています。スクリプトが実行されるのを待つためにすべての時間を費やす必要がないように、実行間でそのデータフレームを常に利用できるようにするための良い解決策はありますか?


2
ええ、これはPythonを使用した私の主な不満の1つです。データフレームを保存および取得する簡単な方法はありません。RとSASは、この点ではるかにユーザーフレンドリーです。
RobertF

回答:


481

最も簡単な方法は、次のものを使用してピクルすることto_pickleです。

df.to_pickle(file_name)  # where to save it, usually as a .pkl

次に、次のコマンドを使用してロードし直すことができます。

df = pd.read_pickle(file_name)

注:0.11.1より前のバージョンでsaveありload、これを行う唯一の方法でした(現在は推奨されておりto_pickleread_pickleそれぞれ推奨されていません)。


もう1つの一般的な選択肢は、大規模なデータセットに対して非常に高速なアクセス時間を提供するHDF5pytables)を使用することです。

store = HDFStore('store.h5')

store['df'] = df  # save it
store['df']  # load it

より高度な戦略については、クックブックで説明しています。


0.13以降は、JSONのより高速な代替手段として、またはPythonオブジェクト/テキストヘビーデータがある場合に相互運用性に優れている可能性があるmsgpackもあります(参照)この質問を)。


8
@geekazoid saveはto_pickleで非推奨になりました(これにより、csvではなくピクルが作成されます。これは、はるかに高速で異なるオブジェクトです)。
アンディヘイデン、

9
@geekazoidロード後にデータを変換する必要がある場合(つまり、文字列/オブジェクトをdatetime64に変換)、保存されたcsvをロードした後に再度実行する必要があり、パフォーマンスが低下します。pickleはデータフレームを現在の状態で保存するため、データとそのフォーマットが保持されます。これにより、パフォーマンスが大幅に向上する可能性があります。
harbun

4
pickleとHDFStoreはどちらも8GBを超えるデータフレームを保存できません。代わりはありますか?
user1700890

1
@ user1700890はランダムなデータ(テキストと配列)から生成して、新しい質問を投稿してみてください。これは正しいことではないと思います/何か不足していると思われます。新しい質問はより多くの注目を集めますが、再現するDataFrameをインクルード/生成してみてください:)
Andy Hayden

1
@YixingLiu事実の後、モードを変更できますstackoverflow.com/a/16249655/1240268
Andy Hayden

100

すでにいくつかの回答はありますが、Pandas DataFramesをシリアル化するいくつかの方法を試してみた素晴らしい比較が見つかりました:Pandas DataFramesを効率的に保存ます。

彼らは比較します:

  • pickle:元のASCIIデータ形式
  • Cライブラリ、cPickle
  • pickle-p2:新しいバイナリ形式を使用します
  • json:standardlib jsonライブラリ
  • json-no-index:jsonに似ていますが、インデックスはありません
  • msgpack:バイナリJSON代替
  • CSV
  • hdfstore:HDF5ストレージ形式

彼らの実験では、2つの列を個別にテストして、1,000,000行のDataFrameをシリアル化します。1つはテキストデータ、もう1つは数値です。彼らの免責事項は言う:

以下の内容がデータに一般化されていると信じてはいけません。自分のデータを見て、自分でベンチマークを実行する必要があります

彼らが参照するテストのソースコードはオンラインで入手できます。このコードは直接動作しませんでしたので、私はあなたがここに来ることができますいくつかのマイナーな変更を、作っ:serialize.pyは、 私は以下の結果を得ました:

時間比較結果

彼らはまた、テキストデータをカテゴリカルに変換するとデータにすると、シリアル化がはるかに高速になるいます。彼らのテストでは約10倍の速さです(テストコードも参照してください)。

編集:ピクルスのCSVよりも高い時間は、使用されているデータ形式で説明できます。デフォルトでpickleは、より大きなデータセットを生成する印刷可能なASCII表現を使用します。ただし、グラフからわかるように、新しいバイナリデータ形式(バージョン2、pickle-p2)を使用したピクルのロード時間ははるかに短くなっています。

その他の参考資料:


1
私はあなたの質問を説明するために私の答えを更新しました。要約すると:デフォルトでは、pickleはデータをASCII形式で格納します。
agold

1
ああ、説明ありがとうございます!注として、pandas DataFrame .to_pickleはpkl.HIGHEST_PROTOCOL(2である必要があります)を使用しているようです
ntg

2
上記のブログのようです(効率的にStore Pandas DataFramesが削除されました。私は.to_pickle()(バイナリストレージを使用)と.to_hdf()(圧縮なしで)を比較しました。目標は速度、HDFのファイルサイズは11倍のPickle、読み込み時間です5x Pickleでした。私のデータは〜7k行x 6列の〜5kファイルで、ほとんどが数値でした
hamx0r

1
ページはまだ存在し、末尾のスラッシュを削除するだけです:Pandas DataFramesを効率的に保存
IanSR

2
@マイクウィリアムソン、私のテストでは、ピクルはHDFよりも5倍高速にロードされ、ディスク容量も1/11でした(つまり、hdfはディスク上で11倍大きく、ピクルがロードしたときの5倍の時間をディスクからロードしました)。これはすべて、pandas 0.22.0を使用するpython 3での作業でした。
hamx0r

35

私が正しく理解していれば、既に使用pandas.read_csv()していますが、スクリプトを編集するたびにファイルをロードする必要がないように開発プロセスをスピードアップしたいと思いますか?私はいくつかの推奨事項を持っています:

  1. pandas.read_csv(..., nrows=1000)開発を行っている間は、CSVファイルの一部のみをロードして、テーブルの最上位ビットのみをロードできます。

  2. スクリプトを編集してリロードするときにパンダテーブルをメモリに保持するように、インタラクティブセッションにipythonを使用します。

  3. csvをHDF5テーブルに変換する

  4. 更新された使用法DataFrame.to_feather()pd.read_feather()、データをR互換のフェザーバイナリ形式で保存する方法(超高速)(私の手ではpandas.to_pickle()、数値データよりもわずかに速く、文字列データの方がはるかに高速です)。

また、stackoverflowに関するこの回答に興味があるかもしれません。


to_feather文字列データでうまく機能する理由を知っていますか?私はベンチマークto_pickleto_feature行い、数値データフレームとピクルで約3倍速くなりました。
zyxue 2018

@zyxue良い質問です。正直なところ、羽毛についてはあまり遊んだことがないので、答えはありません
ノア

20

ピクルスはうまくいきます!

import pandas as pd
df.to_pickle('123.pkl')    #to save the dataframe, df to 123.pkl
df1 = pd.read_pickle('123.pkl') #to load 123.pkl back to the dataframe df

8
生成されたファイルはcsvファイルではないことに注意してください.pkl。@ Andy Haydensの回答で提案されているように、拡張機能を使用することをお勧めします。
agold 2015年

5

フェザー形式のファイルを使用できます。非常に高速です。

df.to_feather('filename.ft')

そして、ライブラリRを使用してデータを直接使用できfeatherます。
James Hirschorn、

4

Pandas DataFramesには、DataFrameのto_pickle保存に役立つ関数があります。

import pandas as pd

a = pd.DataFrame({'A':[0,1,0,1,0],'B':[True, True, False, False, False]})
print a
#    A      B
# 0  0   True
# 1  1   True
# 2  0  False
# 3  1  False
# 4  0  False

a.to_pickle('my_file.pkl')

b = pd.read_pickle('my_file.pkl')
print b
#    A      B
# 0  0   True
# 1  1   True
# 2  0  False
# 3  1  False
# 4  0  False

4

すでに述べたように、さまざまなオプションとファイル形式があります(、データフレームを格納するための HDF5JSONCSV寄木細工SQL)があります。ただし、pickleは一流の市民ではありません(設定によって異なります)。

  1. pickle潜在的なセキュリティリスクです。picklePythonドキュメントを作成します

警告pickleモジュールは、誤ったまたは悪意を持って構築されたデータに対して安全ではありません。信頼できない、または認証されていないソースから受信したデータを抽出しないでください。

  1. pickle遅い。ここここのベンチマークを見つけてください

設定/使用法によっては両方の制限が適用されませんが、pickleパンダデータフレームのデフォルトの永続性としてはお勧めしません。


1

Numpyファイル形式は数値データに対してかなり高速です

numpyファイルは高速で扱いやすいので、使用することをお勧めします。これは、100万ポイントの1列のデータフレームを保存およびロードするための簡単なベンチマークです。

import numpy as np
import pandas as pd

num_dict = {'voltage': np.random.rand(1000000)}
num_df = pd.DataFrame(num_dict)

ipythonの%%timeit魔法の関数を使う

%%timeit
with open('num.npy', 'wb') as np_file:
    np.save(np_file, num_df)

出力は

100 loops, best of 3: 5.97 ms per loop

データをデータフレームに読み込む

%%timeit
with open('num.npy', 'rb') as np_file:
    data = np.load(np_file)

data_df = pd.DataFrame(data)

出力は

100 loops, best of 3: 5.12 ms per loop

悪くない!

短所

python 2を使用してnumpyファイルを保存してから、python 3を使用して開こうとすると問題が発生します(またはその逆)。


6
このソリューションはすべての列名を削除し、すべての整数データを浮動小数点数に変更することに注意してください:(
Joseph Garvin

0

https://docs.python.org/3/library/pickle.html

ピクルプロトコル形式:

プロトコルバージョン0は元の「人間が読める」プロトコルであり、以前のバージョンのPythonと下位互換性があります。

プロトコルバージョン1は古いバイナリ形式で、以前のバージョンのPythonとも互換性があります。

プロトコルバージョン2はPython 2.3で導入されました。新しいスタイルのクラスをより効率的にピクルス化します。プロトコル2による改善については、PEP 307を参照してください。

プロトコルバージョン3はPython 3.0で追加されました。バイトオブジェクトを明示的にサポートしており、Python 2.xでunpickleすることはできません。これはデフォルトのプロトコルであり、他のPython 3バージョンとの互換性が必要な場合に推奨されるプロトコルです。

プロトコルバージョン4はPython 3.4で追加されました。非常に大きなオブジェクトのサポート、より多くの種類のオブジェクトのピクル化、および一部のデータ形式の最適化が追加されます。プロトコル4による改善については、PEP 3154を参照してください。


0

バージョン間のpyarrow互換性

全体的な動きはpyarrow / featherです(pandas / msgpackからの非推奨の警告)。ただし、仕様に一時的な pyarrowでの挑戦があります。pyarrow0.15.1でシリアル化されたデータは、0.16.0で逆シリアル化できませんARROW-7961。シリアル化を使用してredisを使用しているため、バイナリエンコーディングを使用する必要があります。

さまざまなオプションを再テストしました(jupyterノートブックを使用)

import sys, pickle, zlib, warnings, io
class foocls:
    def pyarrow(out): return pa.serialize(out).to_buffer().to_pybytes()
    def msgpack(out): return out.to_msgpack()
    def pickle(out): return pickle.dumps(out)
    def feather(out): return out.to_feather(io.BytesIO())
    def parquet(out): return out.to_parquet(io.BytesIO())

warnings.filterwarnings("ignore")
for c in foocls.__dict__.values():
    sbreak = True
    try:
        c(out)
        print(c.__name__, "before serialization", sys.getsizeof(out))
        print(c.__name__, sys.getsizeof(c(out)))
        %timeit -n 50 c(out)
        print(c.__name__, "zlib", sys.getsizeof(zlib.compress(c(out))))
        %timeit -n 50 zlib.compress(c(out))
    except TypeError as e:
        if "not callable" in str(e): sbreak = False
        else: raise
    except (ValueError) as e: print(c.__name__, "ERROR", e)
    finally: 
        if sbreak: print("=+=" * 30)        
warnings.filterwarnings("default")

データフレームの次の結果(outjupyter変数内)

pyarrow before serialization 533366
pyarrow 120805
1.03 ms ± 43.9 µs per loop (mean ± std. dev. of 7 runs, 50 loops each)
pyarrow zlib 20517
2.78 ms ± 81.8 µs per loop (mean ± std. dev. of 7 runs, 50 loops each)
=+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+=
msgpack before serialization 533366
msgpack 109039
1.74 ms ± 72.8 µs per loop (mean ± std. dev. of 7 runs, 50 loops each)
msgpack zlib 16639
3.05 ms ± 71.7 µs per loop (mean ± std. dev. of 7 runs, 50 loops each)
=+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+=
pickle before serialization 533366
pickle 142121
733 µs ± 38.3 µs per loop (mean ± std. dev. of 7 runs, 50 loops each)
pickle zlib 29477
3.81 ms ± 60.4 µs per loop (mean ± std. dev. of 7 runs, 50 loops each)
=+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+=
feather ERROR feather does not support serializing a non-default index for the index; you can .reset_index() to make the index into column(s)
=+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+=
parquet ERROR Nested column branch had multiple children: struct<x: double, y: double>
=+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+=

羽毛と寄木細工がデータフレームで機能しません。pyarrowを使い続けます。しかし、私は漬物で補います(圧縮なし)。キャッシュストアへの書き込み時、pyarrowおよびpickleのシリアル化されたフォーム。pyarrowの逆シリアル化が失敗した場合、キャッシュのフォールバックからピクルに読み取ります。


これは質問の答えにはなりません
Jason S

0

形式はユースケースによって異なります

  • ノートブックセッション間でDataFrameを保存します- ピクルスに慣れている場合は、羽毛でもかまいません。
  • DataFrameを可能な限り小さいファイルサイズで保存します- 寄木細工またはpickle.gz(データに適したものを確認してください)
  • 非常に大きなDataFrame(1000万行以上)を節約-hdf
  • 他の形式(csvcsv.gz)をサポートしていない別のプラットフォーム(Pythonではない)でデータを読み取ることができる、寄木細工がサポートされているかどうかを確認する
  • 目で確認できるようにする/ Excelを使用する/ Googleスプレッドシート/ Git diff- csv
  • ほぼすべてのRAMを取るDATAFRAME保存- CSV

パンダのファイル形式の比較はこのビデオにあります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.