python - مشكله - لا توجد ذاكرة كافية فوتوشوب




كيف يمكنني تحرير الذاكرة المستخدمة من قبل dataframe الباندا؟ (3)

لدي ملف CSV كبير حقًا افتتحته في الباندا كما يلي ....

import pandas
df = pandas.read_csv('large_txt_file.txt')

بمجرد القيام بذلك ، يزيد استخدام ذاكرتي بمقدار 2 غيغابايت ، وهو أمر متوقع لأن هذا الملف يحتوي على ملايين الصفوف. مشكلتي تأتي عندما أحتاج إلى إطلاق هذه الذاكرة. جريت ....

del df

ومع ذلك ، لم يسقط استخدام ذاكرتي. هل هذه طريقة خاطئة لإطلاق الذاكرة المستخدمة من قبل إطار بيانات الباندا؟ إذا كان كذلك ، ما هي الطريقة الصحيحة؟


كما هو موضح في التعليقات ، هناك بعض الأشياء التي يجب تجربتها: قد تقوم gc.collect (EdChum) بمسح الأشياء ، على سبيل المثال. على الأقل من تجربتي ، هذه الأشياء تعمل أحيانًا وغالبًا لا تعمل.

ومع ذلك ، هناك شيء واحد يعمل دائمًا ، لأنه يتم على مستوى نظام التشغيل وليس اللغة.

افترض أن لديك وظيفة تقوم بإنشاء DataFrame ضخمة وسيطة وإرجاع نتيجة أصغر (والتي قد تكون أيضًا DataFrame):

def huge_intermediate_calc(something):
    ...
    huge_df = pd.DataFrame(...)
    ...
    return some_aggregate

ثم إذا كنت تفعل شيئا مثل

import multiprocessing

result = multiprocessing.Pool(1).map(huge_intermediate_calc, [something_])[0]

ثم يتم تنفيذ الوظيفة في عملية مختلفة . عند اكتمال هذه العملية ، يستعيد نظام التشغيل جميع الموارد التي يستخدمها. لا يوجد شيء حقًا يمكن لبايثون ، جامع القمامة ، فعله لوقف ذلك.


لن يتم حذف del df إذا كان هناك أي إشارة إلى df في وقت الحذف. لذلك تحتاج إلى حذف جميع المراجع إليها مع del df لتحرير الذاكرة.

لذلك يجب حذف جميع المثيلات المرتبطة بـ df لتشغيل مجموعة البيانات المهملة.

استخدم objgragh للتحقق من التمسك بالأشياء.


يعد تقليل استخدام الذاكرة في Python أمرًا صعبًا ، لأن Python لا يُصدر الذاكرة في الواقع إلى نظام التشغيل . إذا قمت بحذف كائنات ، فستتوفر الذاكرة لكائنات Python الجديدة ، ولكن لن تعود free() إلى النظام ( انظر هذا السؤال ).

إذا التزمت بالصفيفات الرقمية المؤلمة ، فسيتم تحرير تلك العناصر ، لكن الكائنات المحاصرة ليست كذلك.

>>> import os, psutil, numpy as np
>>> def usage():
...     process = psutil.Process(os.getpid())
...     return process.get_memory_info()[0] / float(2 ** 20)
... 
>>> usage() # initial memory usage
27.5 

>>> arr = np.arange(10 ** 8) # create a large array without boxing
>>> usage()
790.46875
>>> del arr
>>> usage()
27.52734375 # numpy just free()'d the array

>>> arr = np.arange(10 ** 8, dtype='O') # create lots of objects
>>> usage()
3135.109375
>>> del arr
>>> usage()
2372.16796875  # numpy frees the array, but python keeps the heap big

تقليل عدد قواعد البيانات

تحتفظ Python بذاكرتنا في علامة مائية عالية ، ولكن يمكننا تقليل إجمالي عدد البيانات التي ننشئها. عند تعديل إطار البيانات الخاص بك ، تفضل inplace=True ، لذلك لا تنشئ نسخًا.

مسكتك شائعة أخرى تمسك بنسخ من dataframes التي تم إنشاؤها مسبقًا في ipython:

In [1]: import pandas as pd

In [2]: df = pd.DataFrame({'foo': [1,2,3,4]})

In [3]: df + 1
Out[3]: 
   foo
0    2
1    3
2    4
3    5

In [4]: df + 2
Out[4]: 
   foo
0    3
1    4
2    5
3    6

In [5]: Out # Still has all our temporary DataFrame objects!
Out[5]: 
{3:    foo
 0    2
 1    3
 2    4
 3    5, 4:    foo
 0    3
 1    4
 2    5
 3    6}

يمكنك إصلاح ذلك عن طريق كتابة %reset Out لمسح السجل. بدلاً من ذلك ، يمكنك ضبط مقدار سجل ipython مع ipython --cache-size=5 (الافتراضي هو 1000).

تقليل حجم Dataframe

كلما كان ذلك ممكنًا ، تجنب استخدام أنواع الكائنات.

>>> df.dtypes
foo    float64 # 8 bytes per value
bar      int64 # 8 bytes per value
baz     object # at least 48 bytes per value, often more

يتم محاصر القيم مع كائن dtype ، مما يعني أن مجموعة numpy يحتوي فقط على مؤشر ولديك كائن Python كامل على كومة الذاكرة المؤقتة لكل قيمة في dataframe الخاص بك. وهذا يشمل السلاسل.

بينما تدعم numpy سلاسل ذات حجم ثابت في المصفوفات ، فإن الباندا لا ( فهي تسبب تشويش المستخدم ). هذا يمكن أن تحدث فرقا كبيرا:

>>> import numpy as np
>>> arr = np.array(['foo', 'bar', 'baz'])
>>> arr.dtype
dtype('S3')
>>> arr.nbytes
9

>>> import sys; import pandas as pd
>>> s = pd.Series(['foo', 'bar', 'baz'])
dtype('O')
>>> sum(sys.getsizeof(x) for x in s)
120

قد ترغب في تجنب استخدام أعمدة السلسلة ، أو العثور على طريقة لتمثيل بيانات السلسلة كأرقام.

إذا كان لديك إطار بيانات يحتوي على العديد من القيم المتكررة (NaN شائع جدًا) ، فيمكنك استخدام بنية بيانات متفرقة لتقليل استخدام الذاكرة:

>>> df1.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 39681584 entries, 0 to 39681583
Data columns (total 1 columns):
foo    float64
dtypes: float64(1)
memory usage: 605.5 MB

>>> df1.shape
(39681584, 1)

>>> df1.foo.isnull().sum() * 100. / len(df1)
20.628483479893344 # so 20% of values are NaN

>>> df1.to_sparse().info()
<class 'pandas.sparse.frame.SparseDataFrame'>
Int64Index: 39681584 entries, 0 to 39681583
Data columns (total 1 columns):
foo    float64
dtypes: float64(1)
memory usage: 543.0 MB

عرض استخدام الذاكرة

يمكنك عرض استخدام الذاكرة ( docs ):

>>> df.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 39681584 entries, 0 to 39681583
Data columns (total 14 columns):
...
dtypes: datetime64[ns](1), float64(8), int64(1), object(4)
memory usage: 4.4+ GB

اعتبارا من الباندا 0.17.1 ، يمكنك أيضا القيام df.info(memory_usage='deep') لرؤية استخدام الذاكرة بما في ذلك الكائنات.





memory