2016-07-28 7 views
3

私は、データにNaNがないことを確認して、もう一度CSVとして別の列サブセットを出力しなければならない40GBのCSVファイルを持っています。私はパンダを使用することを選んだ、と私の実装の最小限の例では、この(機能output_different_formats内側)のようになります。40GバイトのCSVを読み書きするときのMemoryError ...どこにリークがありますか?

# column_names is a huge list containing the column union of all the output 
# column subsets 
scen_iter = pd.read_csv('mybigcsv.csv', header=0, index_col=False, 
         iterator=True, na_filter=False, 
         usecols=column_names) 
CHUNKSIZE = 630100 
scen_cnt = 0 
output_names = ['formatA', 'formatB', 'formatC', 'formatD', 'formatE'] 
# column_mappings is a dictionary mapping the output names to their 
# respective column subsets. 
while scen_cnt < 10000: 
    scenario = scen_iter.get_chunk(CHUNKSIZE) 
    if scenario.isnull().values.any(): 
     # some error handling (has yet to ever occur) 
    for item in output_names: 
     scenario.to_csv(item, float_format='%.8f', 
         columns=column_mappings[item], 
         mode='a', header=True, index=False, compression='gzip') 

    scen_cnt+=100 

私は.get_chunk()とチャンク内のファイルを反復処理していますように私は、これは安全なメモリ単位だと思いました一度にDataFrameにCSV全体を配置することはなく、それぞれのファイルの最後に次のチャンクを追加するだけです。

ただし、出力の生成に約3.5 GBとは、私のプログラムは、長いトレースバックは、なぜ私はここにMemoryErrorを取得しています以下の

File "D:\AppData\A\MRM\Eric\Anaconda\lib\site-packages\pandas\core\common.py", line 838, in take_nd 
    out = np.empty(out_shape, dtype=dtype) 
MemoryError 

で終わると.to_csvラインで次のMemoryErrorで墜落しましたか?プログラムのどこかにメモリリークがあるのですか、何かを誤解していますか?あるいは、その特定のチャンクのためにCSVへの書き込みをランダムに失敗するようにプログラムを誘惑することができますか?チャンクサイズを減らすことを検討するべきでしょうか?

完全トレースバック

Traceback (most recent call last): 
    File "D:/AppData/A/MRM/Eric/output_formats.py", line 128, in <module> 
    output_different_formats(real_world=False) 
    File "D:/AppData/A/MRM/Eric/output_formats.py", line 50, in clocked 
    result = func(*args, **kwargs) 
    File "D:/AppData/A/MRM/Eric/output_formats.py", line 116, in output_different_formats 
    mode='a', header=True, index=False, compression='gzip') 
    File "D:\AppData\A\MRM\Eric\Anaconda\lib\site-packages\pandas\core\frame.py", line 1188, in to_csv 
    decimal=decimal) 
    File "D:\AppData\A\MRM\Eric\Anaconda\lib\site-packages\pandas\core\format.py", line 1293, in __init__ 
    self.obj = self.obj.loc[:, cols] 
    File "D:\AppData\A\MRM\Eric\Anaconda\lib\site-packages\pandas\core\indexing.py", line 1187, in __getitem__ 
    return self._getitem_tuple(key) 
    File "D:\AppData\A\MRM\Eric\Anaconda\lib\site-packages\pandas\core\indexing.py", line 720, in _getitem_tuple 
    retval = getattr(retval, self.name)._getitem_axis(key, axis=i) 
    File "D:\AppData\A\MRM\Eric\Anaconda\lib\site-packages\pandas\core\indexing.py", line 1323, in _getitem_axis 
    return self._getitem_iterable(key, axis=axis) 
    File "D:\AppData\A\MRM\Eric\Anaconda\lib\site-packages\pandas\core\indexing.py", line 966, in _getitem_iterable 
    result = self.obj.reindex_axis(keyarr, axis=axis, level=level) 
    File "D:\AppData\A\MRM\Eric\Anaconda\lib\site-packages\pandas\core\frame.py", line 2519, in reindex_axis 
    fill_value=fill_value) 
    File "D:\AppData\A\MRM\Eric\Anaconda\lib\site-packages\pandas\core\generic.py", line 1852, in reindex_axis 
    {axis: [new_index, indexer]}, fill_value=fill_value, copy=copy) 
    File "D:\AppData\A\MRM\Eric\Anaconda\lib\site-packages\pandas\core\generic.py", line 1876, in _reindex_with_indexers 
    copy=copy) 
    File "D:\AppData\A\MRM\Eric\Anaconda\lib\site-packages\pandas\core\internals.py", line 3157, in reindex_indexer 
    indexer, fill_tuple=(fill_value,)) 
    File "D:\AppData\A\MRM\Eric\Anaconda\lib\site-packages\pandas\core\internals.py", line 3238, in _slice_take_blocks_ax0 
    new_mgr_locs=mgr_locs, fill_tuple=None)) 
    File "D:\AppData\A\MRM\Eric\Anaconda\lib\site-packages\pandas\core\internals.py", line 853, in take_nd 
    allow_fill=False) 
    File "D:\AppData\A\MRM\Eric\Anaconda\lib\site-packages\pandas\core\common.py", line 838, in take_nd 
    out = np.empty(out_shape, dtype=dtype) 
MemoryError 
+1

ループ内のガベージコレクタ( 'gc.collect()')を呼び出そうとするかもしれません。回避策として、64ビットバージョンのPythonを試すこともできます。 –

+0

@ Jean-FrançoisFabre 'gc.collect()'を使って試してみると、それがもう数時間で成功したかどうかはわかりません。 64ビットPythonがなぜ役立つのでしょうか? –

+0

64ビットのPythonでは、より多くのメモリ割り当てが可能です(もちろん、システム上の物理メモリとスワップ、64ビットのウィンドウが必要です)。これはメモリリークを修正するものではありませんが、プログラムが終了するまで遅くなります。 –

答えて

2

今のところ解決策は、手動でgc.collect()

while scen_cnt < 10000: 
    scenario = scen_iter.get_chunk(CHUNKSIZE) 
    if scenario.isnull().values.any(): 
     # some error handling (has yet to ever occur) 
    for item in output_names: 
     scenario.to_csv(item, float_format='%.8f', 
         columns=column_mappings[item], 
         mode='a', header=True, index=False, compression='gzip') 
     gc.collect() 
    gc.collect() 

でガベージコレクタを呼び出すようにしていたメモリ消費量は、しかし、それは、これらの行を追加した後、安定したまま私のにはまだわかりません。この方法ではメモリの問題があります。

+0

ガベージコレクタを呼び出すことは、このような場合にあなたを助けないので、メモリリークのようではありません。あなたが使用している多様なライブラリ内で暗黙的にメモリの割り当てがどのように行われているかは、まさにその可能性があります。私はライブラリユーザーとして、あなたはそれについて何かをすることができることに驚くだろう。 –

+0

@BenDadsetan面白い、洞察力ありがとう! –

+0

私はあなたのケースでは、図書館のユーザーが何をすべきかを学びたいと思っています。 :)しかし、私はあなたがここでメモリリークを作成したと想像することはできませんし、あなたのライブラリでした。 –

関連する問題