2016-07-28 9 views
3

Ich habe eine 40GB CSV-Datei, die ich mit verschiedenen Spaltenuntergruppen als CSVs wieder ausgeben muss, mit einer Überprüfung, dass es keine NaN s in den Daten gibt. Ich entschied ich Pandas, und ein minimales Beispiel für meine Implementierung sieht wie folgt aus zu verwenden (in einer Funktion output_different_formats):MemoryError beim Lesen und Schreiben einer 40 GB CSV ... wo ist mein Leck?

# 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 

ich gedacht war sicher Speicher-weise, wie ich über die Datei in Brocken am Iterieren mit .get_chunk() und legen Sie niemals die gesamte CSV-Datei gleichzeitig in einen DataFrame, sondern fügen Sie einfach den nächsten Chunk an das Ende der jeweiligen Datei an.

jedoch etwa 3,5 GBs in die Ausgang Generation, stürzte mein Programm mit dem folgende Memory in der .to_csv Linie mit einem langen Traceback mit den folgenden

Endung
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 

Warum bin ich hier ein Memory bekommen? Habe ich irgendwo in meinem Programm ein Speicherleck oder verkenne ich etwas? Oder könnte das Programm dazu gebracht werden, beim Schreiben in die CSV-Datei für diesen bestimmten Block nur zufällig fehlzuschlagen, und vielleicht sollte ich erwägen, die Chunksize zu reduzieren?

Volltraceback:

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

Vielleicht könnten Sie versuchen, den Garbage Collector in der Schleife aufzurufen ('gc.collect()'). Als Workaround können Sie auch eine 64-Bit-Version von Python ausprobieren. –

+0

@ Jean-FrançoisFabre Wenn ich jetzt mit 'gc.collect()' versuche, weiß ich nicht, ob es noch ein paar Stunden erfolgreich war. Warum könnte 64-Bit-Python helfen? –

+0

64-Bit-Python ermöglicht mehr Speicherzuweisung (natürlich benötigen Sie den physischen Speicher/Swap auf Ihrem System und ein 64-Bit-Windows). Dies wird das Speicherleck nicht beheben, wird es aber hoffentlich bis zur Beendigung Ihres Programms verzögern. –

Antwort

2

Die Lösung für jetzt wurde 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() 

der Speicherverbrauch stabil bleibt der Garbage Collector manuell aufrufen, nachdem diese Zeilen hinzufügen, aber es ist noch unklar zu meinem warum gibt es ein Speicherproblem mit diesem Ansatz.

+0

Es scheint nicht um ein Speicherleck zu gehen, weil das Aufrufen des Garbage Collectors in einem solchen Fall nicht helfen würde. Es ist nur wahrscheinlich, wie die Speicherzuweisung implizit in den verschiedenen Bibliotheken erfolgt, die Sie verwenden. Ich wäre überrascht, dass Sie als Bibliotheksbenutzer etwas dagegen tun können. –

+0

@BenDadsetan Interessant, danke für die Einsicht! –

+0

Ich würde gerne lernen, was ein Bibliotheksbenutzer in Ihrem Fall tun soll. :) Aber ich kann mir nicht vorstellen, dass du hier irgendein Speicherleck erzeugt hast, genauso wenig wie deine Bibliotheken. –