web-dev-qa-db-ja.com

メモリエラーなしでピクルダンプ巨大ファイル

私は、すでに知られていることに基づいて特定の事柄が起こる確率を基本的に調整するプログラムを持っています。データのファイルは、_Dictionary.txt_のpickle辞書オブジェクトとして既に保存されています。

問題は、プログラムを実行するたびに_Dictionary.txt_を取り込み、それを辞書オブジェクトに変換し、編集して_Dictionary.txt_を上書きすることです。 _Dictionary.txt_は123 MBであるため、これはかなりのメモリを消費します。ダンプするときにMemoryErrorが返されます。それを引っ張るとすべてがうまくいくように見えます。

  • 編集を行うより良い(より効率的な)方法はありますか? (おそらく、ファイル全体を毎回上書きする必要はありません)

  • gcモジュールを使用して)ガベージコレクションを呼び出す方法はありますか? (gc.enable()で既に自動有効化されています)

  • readlines()の他に、行ごとに読むことができることを知っています。プログラムに完全に完成した辞書オブジェクトファイルがある場合に、辞書を1行ずつ段階的に編集する方法はありますか。

  • 他のソリューションはありますか?

お時間をいただきありがとうございます。

23
user2543682

私は同じ問題を抱えていました。私はjoblibを使用し、作業は完了しました。誰かが他の可能性を知りたい場合。

モデルをディスクに保存します

from sklearn.externals import joblib
filename = 'finalized_model.sav'
joblib.dump(model, filename)  

しばらくして...ディスクからモデルをロードします

loaded_model = joblib.load(filename)
result = loaded_model.score(X_test, Y_test) 

print(result)
15
Ch HaXam

私はkleptoというパッケージの作成者です(また、dillの作成者でもあります)。 kleptoは、非常に簡単な方法でオブジェクトを保存および取得するために構築され、データベース、メモリキャッシュ、およびディスク上のストレージへのシンプルな辞書インターフェイスを提供します。以下に、エントリごとに1つのファイルがあるファイルシステムディレクトリである「ディレクトリアーカイブ」に大きなオブジェクトを保存する方法を示します。オブジェクトをシリアル化することを選択しますが(低速ですが、dillを使用するため、ほとんどすべてのオブジェクトを格納できます)、キャッシュを選択します。メモリキャッシュを使用すると、アーカイブ全体をメモリに保持しなくても、ディレクトリアーカイブにすばやくアクセスできます。データベースやファイルとのやり取りは遅くなる可能性がありますが、メモリとのやり取りは高速です...そして、アーカイブから好きなようにメモリキャッシュを追加できます。

>>> import klepto
>>> d = klepto.archives.dir_archive('stuff', cached=True, serialized=True)
>>> d
dir_archive('stuff', {}, cached=True)
>>> import numpy
>>> # add three entries to the memory cache
>>> d['big1'] = numpy.arange(1000)
>>> d['big2'] = numpy.arange(1000)
>>> d['big3'] = numpy.arange(1000)
>>> # dump from memory cache to the on-disk archive
>>> d.dump()
>>> # clear the memory cache
>>> d.clear()
>>> d
dir_archive('stuff', {}, cached=True)
>>> # only load one entry to the cache from the archive
>>> d.load('big1')
>>> d['big1'][-3:]
array([997, 998, 999])
>>> 

kleptoは、大量のストレージへの高速で柔軟なアクセスを提供します。アーカイブが並列アクセスを許可している場合(データベースなど)、結果を並列で読み取ることができます。また、異なる並列プロセスまたは異なるマシンで結果を共有するのも簡単です。ここで、同じディレクトリアーカイブを指す2番目のアーカイブインスタンスを作成します。 2つのオブジェクト間でキーを渡すのは簡単で、異なるプロセスと同じように機能します。

>>> f = klepto.archives.dir_archive('stuff', cached=True, serialized=True)
>>> f
dir_archive('stuff', {}, cached=True)
>>> # add some small objects to the first cache  
>>> d['small1'] = lambda x:x**2
>>> d['small2'] = (1,2,3)
>>> # dump the objects to the archive
>>> d.dump()
>>> # load one of the small objects to the second cache
>>> f.load('small2')
>>> f       
dir_archive('stuff', {'small2': (1, 2, 3)}, cached=True)

また、さまざまなレベルのファイル圧縮から選択したり、ファイルをメモリマップするかどうかを選択したりできます。ファイルバックエンドとデータベースバックエンドの両方に対して、さまざまなオプションがあります。ただし、インターフェイスは同じです。

ガベージコレクションと辞書の一部の編集に関する他の質問に関しては、メモリキャッシュからオブジェクトを個別にロードおよび削除、ダンプ、ロード、およびアーカイブと同期できるため、両方ともkleptoで可能です。バックエンド、または他の辞書メソッドのいずれか。

詳細なチュートリアルはこちらをご覧ください: https://github.com/mmckerns/tlkklp

ここでkleptoを取得: https://github.com/uqfoundation

13
Mike McKerns

メモリエラーが発生したため、protocol = 2を使用して解決しました。

cPickle.dump(obj, file, protocol=2)

3
denfromufa

これはどう?

import cPickle as pickle
p = pickle.Pickler(open("temp.p","wb")) 
p.fast = True 
p.dump(d) # d could be your dictionary or any file
2
richie

ストリーミングピクルを使用してみましたか: https://code.google.com/p/streaming-pickle/

ストリーミングピクルに切り替えて、同様のメモリエラーを解決しました。

2
Chris Wheadon

キーと値が文字列の場合、Python標準ライブラリ。 anydbm モジュールドキュメントの例で利用可能な埋め込み永続キー値ストレージエンジンのいずれかを使用できます。

import anydbm

# Open database, creating it if necessary.
db = anydbm.open('cache', 'c')

# Record some values
db['www.python.org'] = 'Python Website'
db['www.cnn.com'] = 'Cable News Network'

# Loop through contents.  Other dictionary methods
# such as .keys(), .values() also work.
for k, v in db.iteritems():
    print k, '\t', v

# Storing a non-string key or value will raise an exception (most
# likely a TypeError).
db['www.yahoo.com'] = 4

# Close when done.
db.close()
2
Imran

私は最近この問題を抱えていました。 ASCIIとバイナリプロトコル2を使用してcpickleを試行した後、20ギガバイト以上のデータでトレーニングされたSci-kit LearnのSVMがメモリエラーのために酸洗いされていないことがわかりました。 Dillは辞書に多くの改善を加えることはありませんが、ストリーミングには役立つ可能性があります。

import dill

with open(path,'wb') as fp:
    dill.dump(outpath,fp)
    dill.load(fp)

効率が問題になる場合は、データベースにロード/保存してみてください。この場合、ストレージソリューションが問題になる可能性があります。 123 mb Pandasで問題ありません。ただし、マシンのメモリが限られている場合、SQLは通常マルチスレッドサポートを使用して、データに対する高速で最適化されたバッグ操作を提供します。ポリカーネルsvmを保存しました。

1

これは些細なことのように思えるかもしれませんが、64ビットPythonでない場合は使用してください。

1
lyron

上記の答えのどれも私にとってはうまくいきませんでした。私は、Hickleを使用することになりました。これは、HDF5に基づいたpickleのドロップイン代替品です。ピクルに保存する代わりに、データをHDF5ファイルに保存します。 APIはほとんどのユースケースで同一であり、圧縮などの非常に優れた機能を備えています。

pip install hickle

例:

# Create a numpy array of data
array_obj = np.ones(32768, dtype='float32')

# Dump to file
hkl.dump(array_obj, 'test.hkl', mode='w')

# Load data
array_hkl = hkl.load('test.hkl')
1
gidim