programing tip

Pandas 데이터 프레임에서 사용하는 메모리를 어떻게 해제합니까?

itbloger 2020. 10. 17. 10:02
반응형

Pandas 데이터 프레임에서 사용하는 메모리를 어떻게 해제합니까?


다음과 같이 팬더에서 연 정말 큰 csv 파일이 있습니다 ....

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

이렇게하면 메모리 사용량이 2GB만큼 증가하는데, 이는이 파일에 수백만 개의 행이 포함되어 있기 때문입니다. 이 메모리를 해제해야 할 때 문제가 발생합니다. 달렸어 ....

del df

그러나 내 메모리 사용량은 떨어지지 않았습니다. 판다 데이터 프레임에서 사용하는 메모리를 해제하는 잘못된 접근 방식입니까? 그렇다면 올바른 방법은 무엇입니까?


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

데이터 프레임 수 줄이기

파이썬은 우리의 메모리를 높은 워터 마크로 유지하지만 우리가 만드는 총 데이터 프레임 수를 줄일 수 있습니다. 데이터 프레임을 수정할 때를 선호 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).

데이터 프레임 크기 줄이기

가능하면 개체 dtype을 사용하지 마십시오.

>>> 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 객체가 있습니다. 여기에는 문자열이 포함됩니다.

Whilst numpy supports fixed-size strings in arrays, pandas does not (it's caused user confusion). This can make a significant difference:

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

You may want to avoid using string columns, or find a way of representing string data as numbers.

If you have a dataframe that contains many repeated values (NaN is very common), then you can use a sparse data structure to reduce memory usage:

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

Viewing Memory Usage

You can view the memory usage (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

As of pandas 0.17.1, you can also do df.info(memory_usage='deep') to see memory usage including objects.


As noted in the comments, there are some things to try: gc.collect (@EdChum) may clear stuff, for example. At least from my experience, these things sometimes work and often don't.

There is one thing that always works, however, because it is done at the OS, not language, level.

Suppose you have a function that creates an intermediate huge DataFrame, and returns a smaller result (which might also be a DataFrame):

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

Then if you do something like

import multiprocessing

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

Then the function is executed at a different process. When that process completes, the OS retakes all the resources it used. There's really nothing Python, pandas, the garbage collector, could do to stop that.


This solves the problem of releasing the memory for me!!!

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

the data-frame will be explicitly set to null


del df will not be deleted if there are any reference to the df at the time of deletion. So you need to to delete all the references to it with del df to release the memory.

So all the instances bound to df should be deleted to trigger garbage collection.

Use objgragh to check which is holding onto the objects.

참고URL : https://stackoverflow.com/questions/39100971/how-do-i-release-memory-used-by-a-pandas-dataframe

반응형