2017-07-24 19 views
6

मैं एक प्रोग्राम है जो बार-बार नीचे की तरह एक पांडा डेटा फ्रेम पर लूप है खोजने के लिए कैसे:पांडा के साथ स्मृति रिसाव

monts = [some months] 

for month in months: 
    df = original_df[original_df.month == month].copy() 
    result = some_function(df) 
    print(result) 

हालांकि, स्मृति जो यात्रा प्रति आवश्यक है रहता है बढ़ाने के लिए

          types | # objects | total size 
================================================ | =========== | ============ 
      <class 'pandas.core.frame.DataFrame |   22 |  6.54 GB 
       <class 'pandas.core.series.Series |  1198 |  4.72 GB 
          <class 'numpy.ndarray |  1707 | 648.19 MB 
    <class 'pandas.core.categorical.Categorical |   238 | 368.90 MB 
      <class 'pandas.core.indexes.base.Index |   256 | 312.03 MB 

================================================ | =========== | ============ 
      <class 'pandas.core.frame.DataFrame |   30 |  9.04 GB 
       <class 'pandas.core.series.Series |  2262 |  7.29 GB 
          <class 'numpy.ndarray |  2958 | 834.49 MB 
    <class 'pandas.core.categorical.Categorical |   356 | 569.39 MB 
      <class 'pandas.core.indexes.base.Index |   380 | 481.21 MB 

क्या आपके पास कुछ सुझाव हैं कि स्मृति रिसाव कैसे ढूंढें?

संपादित

ध्यान दें, मैन्युअल रूप से प्रत्येक यात्रा में मदद नहीं करता पर gc.collect() बुला।

संपादित 2

एक न्यूनतम नमूना यहाँ है:

import pandas as pd 
from numpy.random import randn 
df = pd.DataFrame(randn(10000,3),columns=list('ABC')) 
for i in range(10): 
    print(i) 
    something = df.copy() 
    print('#########################') 
    print('trying to limit memory pressure') 
    from pympler import muppy, summary 
    all_objects = muppy.get_objects() 
    sum1 = summary.summarize(all_objects) 
    summary.print_(sum1) 
    print('#########################') 

जैसा कि आप देख इस स्मृति खपत में वृद्धि की कटाई। 10 पुनरावृत्तियों के बाद पहली बार 9 एमबी से शुरू होने से पहले ही यह 30 एमबी का उपयोग कर रहा है।

संपादित 3

वास्तव में, @Steven से टिप्पणी एक बिंदु

for i in range(10): 
    something = df.copy() 
    foo_thing = summary.summarize(muppy.get_objects()) 
    summary.print_(foo_thing) 

समस्या दिखा रहा है, जबकि

for i in range(10): 
    something = df.copy() 
    summary.print_(summary.summarize(muppy.get_objects())) 

ठीक काम कर रहा है हो सकता है। मैं इन सभी चरों को कैसे ढूंढ सकता हूं जो समस्याएं पैदा करते हैं? मुझे लगता है कि यह मेरे असली कोड में विशेष रूप से महत्वपूर्ण है, इनमें से कुछ कुछ बड़े बड़े pandas.Dataframes हैं।

संपादित 4

जब मैन्युअल रूप से अन्य स्क्रिप्ट ठीक रूप में अच्छी तरह काम कर रहा है foo_thing = None की एक पंक्ति जोड़ने। सवाल बनी हुई है - ऐसे सभी मामलों को कुशलतापूर्वक कैसे ढूंढें। क्या पाइथन स्वचालित रूप से उपयोग किए गए चर को स्वचालित रूप से पहचानना नहीं चाहिए?

संपादित 5

जब की तरह एक क्रिया पेश:

def do_some_stuff(): 
    foo_thing = summary.summarize(muppy.get_objects()) 
    summary.print_(foo_thing) 

for i in range(10): 
    something = df.copy() 
    do_some_stuff() 

स्मृति रिसाव भी तय किया जा रहा है।

संपादित करें 6

असल में, स्मृति रिसाव तय नहीं है। अच्छी बात यह है कि summary अब स्मृति की खपत में भारी वृद्धि दर्ज नहीं करता है। बुरी बात यह है कि: कार्य प्रबंधक/गतिविधि मॉनीटर मुझे अन्यथा बताता है - और पाइथन प्रोग्राम किसी बिंदु पर क्रैश हो रहा है।

+0

मुझे यह सुनिश्चित नहीं है कि यह सहायक है: https://stackoverflow.com/questions/14224068/memory-leak-using-pandas-dataframe –

+0

यदि आप लूप सामग्री को फ़ंक्शन के अंदर रखते हैं तो क्या आप वही व्यवहार देखते हैं? – Aaron

+0

शायद मैं पांडों द्वारा कब्जा कर लिया गया सभी मेमोरी मैन्युअल रूप से मुक्त कर सकता हूं और डिस्क से 'original_df' की ताजा प्रति पुनः लोड कर सकता हूं? –

उत्तर

0

मैंने कम से कम नमूना का उपयोग किया है और पाइप्लर से tracker का उपयोग करके इसे थोड़ा संशोधित किया है, ताकि लूप के सेट को निष्पादित करने के बाद अंतर देखने के लिए, लेकिन 10.000 लूप के बाद भी, मुझे कोई मेमोरी रिसाव दिखाई नहीं दे रहा है।

यह पायथन 3.6.0, नम्पी 1.13.1 और पांडस 0.20.3 के साथ परीक्षण किया गया था।

तो आपके द्वारा प्रदान किया गया न्यूनतम नमूना इस मुद्दे को दोहराना नहीं है, या समस्या संस्करण निर्भर है।

import pandas as pd 
from numpy.random import randn 
from pympler import tracker 
from tqdm import tqdm_notebook 


df = pd.DataFrame(randn(10000,3),columns=list('ABC')) 

tr_initial = tracker.SummaryTracker() 

for i in tqdm_notebook(range(10000)): 
    something = df.copy() 

tr_initial.print_diff() 

आउटपुट:

            types | # objects | total size 
====================================================== | =========== | ============ 
              <class 'dict |   78 |  28.73 KB 
              <class 'list |   36 |  4.59 KB 
       <class 'traitlets.config.loader.Config |   17 |  4.25 KB 
             <class 'bytes |   22 |  2.65 KB 
              <class 'str |   9 | 771  B 
              <class 'cell |   15 | 720  B 
             <class 'tuple |   11 | 704  B 
            function (<lambda>) |   4 | 544  B 
             <class 'method |   7 | 448  B 
              <class 'code |   3 | 432  B 
         <class 'ipykernel.comm.comm.Comm |   7 | 392  B 
    <class 'ipywidgets.widgets.widget.CallbackDispatcher |   3 | 168  B 
     <class 'ipywidgets.widgets.widget_layout.Layout |   3 | 168  B 
           function (store_info) |   1 | 136  B 
           function (null_wrapper) |   1 | 136  B 
+0

यहां मेरे सिस्टम से लॉग हैं: https://gist.github.com/geoHeil/ae3c235595ff3adb3ad73407eab5ad53 –

0

इसके बजाय प्रतियां बनाने की, मैं GroupBy से अधिक पुनरावृति होगी। क्या यह आपकी समस्या को ठीक करता है?

for month, df in original_df.groupby('month'): 
    result = some_function(df) 
    print(result) 
+0

नहीं। लेकिन इस बीच मुझे एहसास हुआ कि पांडा नहीं बल्कि उपकरण ने समस्या का कारण बना दिया –

0

समस्या स्कॉइंग के साथ है। जब आप लूप में कोई नई ऑब्जेक्ट बनाते हैं, तो लूप समाप्त होने पर इसे सुलभ माना जाता है। यही कारण है कि (मुझे लगता है), कचरा कलेक्टर कचरा संग्रह के लिए copy का उपयोग कर बनाई गई वस्तुओं को चिह्नित नहीं करता है। जब आप फ़ंक्शन के अंदर नई ऑब्जेक्ट्स बनाते हैं, तो वे ऑब्जेक्ट फ़ंक्शन स्कोप तक सीमित होते हैं और फ़ंक्शन के बाहर उपलब्ध नहीं होते हैं। यही कारण है कि वे एकत्र किए जाते हैं।

आपने बताया कि foo_thing = None असाइन करने से समस्या हल हो जाती है। ऐसा इसलिए होता है क्योंकि foo_thing को किसी अन्य ऑब्जेक्ट (None) पर इंगित करके अब कोई वैरिएबल नहीं है जो डेटा फ्रेम को संदर्भित करता है। मैं एक समान दृष्टिकोण का उपयोग करता हूं लेकिन foo_thing = None के बजाय, मैं del foo_thing करता हूं। सब के बाद, Explicit is better than implicit

संबंधित मुद्दे