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




pandas memory (4)

هذا يحل مشكلة إطلاق الذاكرة بالنسبة لي !!!

del [[df_1,df_2]]
gc.collect()
df_1=pd.DataFrame()
df_2=pd.DataFrame()

سيتم تعيين إطار البيانات بشكل صريح إلى قيمة خالية

لدي ملف CSV كبيرة حقا أن فتحت في الباندا على النحو التالي ....

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

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

del df

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


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

إذا التزمت بمصفوفات numry numry ، يتم تحريرها ، ولكن لا يتم تخزين الكائنات المعبأة.

>>> 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

تقليل عدد من Dataframes

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

آخر مسكتك شائع هو الاحتفاظ بنسخ من صفحات البيانات التي تم إنشاؤها مسبقا في 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

كلما أمكن ، تجنب استخدام dtypes الكائن.

>>> 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

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

إذا كان لديك dataframe يحتوي على العديد من القيم المتكررة (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') لمشاهدة استخدام الذاكرة بما في ذلك الكائنات.


كما هو موضح في التعليقات ، هناك بعض الأشياء التي يمكنك تجربتها: 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 للتحقق من التمسك بالكائنات.







memory