programing

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

skycolor 2023. 9. 4. 19:40
반응형

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

저는 다음과 같이 판다에서 열었던 정말 큰 csv 파일을 가지고 있습니다.

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

이 작업을 수행하면 메모리 사용량이 2GB 증가합니다. 이 파일에는 수백만 개의 행이 포함되어 있기 때문입니다.제 문제는 이 메모리를 해제해야 할 때 발생합니다.도망쳤어요...

del df

하지만, 제 기억력은 떨어지지 않았습니다.이것이 판다 데이터 프레임에서 사용하는 메모리를 해제하는 잘못된 접근 방식입니까?그렇다면 적절한 방법은 무엇입니까?

Python은 실제로 메모리를 운영 체제에 다시 릴리스하지 않기 때문에 Python에서 메모리 사용을 줄이는 것은 어렵습니다.개체를 삭제하면 메모리를 새 Python 개체에 사용할 수 있지만 사용할 수 없습니다.free()시스템으로 돌아갑니다( 질문 참조).

숫자 numpy 배열을 고수하면 해당 배열은 해제되지만 상자에 들어 있는 개체는 해제되지 않습니다.

>>> import os, psutil, numpy as np # psutil may need to be installed
>>> def usage():
...     process = psutil.Process(os.getpid())
...     return process.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복사본을 만들지 않습니다.

또 다른 흔한 문제는 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

개체와 유형이 있는 값은 상자로 표시됩니다. 즉, numpy 배열에는 포인터만 포함되어 있고 힙에는 데이터 프레임의 모든 값에 대한 전체 Python 개체가 있습니다.여기에는 문자열이 포함됩니다.

numpy는 배열에서 고정 크기의 문자열을 지원하는 반면, Panda는 지원하지 않습니다(사용자 혼란을 야기함).이로 인해 다음과 같은 큰 차이가 발생할 수 있습니다.

>>> 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')개체를 포함한 메모리 사용량을 확인합니다.

해 볼 : 설에서언것다같은몇볼시수다있습니가해도지명음.gc.collect예를 들어 (@EdChum)은 삭제할 수 있습니다.적어도 제 경험으로 볼 때, 이런 것들은 가끔은 효과가 있고 종종 그렇지 않습니다.

그러나 언어가 아닌 OS 수준에서 수행되기 때문에 항상 작동하는 한 가지가 있습니다.

중간 크기의 거대한 데이터 프레임을 만들고 더 작은 결과(데이터 프레임일 수도 있음)를 반환하는 함수가 있다고 가정합니다.

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

그럼 당신이 그런 짓을 하면,

import multiprocessing

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

그런 다음 다른 프로세스에서 기능이 실행됩니다.이 프로세스가 완료되면 OS는 사용한 모든 리소스를 다시 가져옵니다.Python, 팬더, 쓰레기 수거업자는 그것을 막기 위해 할 수 있는 일이 없습니다.

이것은 나를 위해 메모리를 푸는 문제를 해결합니다!!!

import gc
import pandas as pd

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

데이터 프레임이 명시적으로 null로 설정됩니다.

상술한 바와 같이

먼저, 데이터 프레임의 자체 참조가 삭제됩니다. 즉, 데이터 프레임의 모든 참조가 가비지 콜렉터(gc.collect()에 의해 수집된 후 모든 참조를 빈 데이터 프레임으로 명시적으로 설정한 후 데이터 프레임을 더 이상 파이썬할 수 없습니다.

쓰레기 수거기의 작동에 대한 더 많은 것은 https://stackify.com/python-garbage-collection/ 에서 잘 설명되어 있습니다.

del df 경우 .df삭제할 때그래서 당신은 그것에 대한 모든 참조를 삭제해야 합니다.del df메모리를 해제할 수 있습니다.

따라서 가비지 수집을 트리거하려면 df에 바인딩된 모든 인스턴스를 삭제해야 합니다.

objgragh를 사용하여 어떤 것이 물체를 고정하고 있는지 확인합니다.

Pandas의 메모리 할당에 영향을 미치는 glibc에 문제가 있는 것 같습니다. https://github.com/pandas-dev/pandas/issues/2659

문제에 대해 자세히 설명한 원숭이 패치로 문제가 해결되었습니다.

# monkeypatches.py

# Solving memory leak problem in pandas
# https://github.com/pandas-dev/pandas/issues/2659#issuecomment-12021083
import pandas as pd
from ctypes import cdll, CDLL
try:
    cdll.LoadLibrary("libc.so.6")
    libc = CDLL("libc.so.6")
    libc.malloc_trim(0)
except (OSError, AttributeError):
    libc = None

__old_del = getattr(pd.DataFrame, '__del__', None)

def __new_del(self):
    if __old_del:
        __old_del(self)
    libc.malloc_trim(0)

if libc:
    print('Applying monkeypatch for pd.DataFrame.__del__', file=sys.stderr)
    pd.DataFrame.__del__ = __new_del
else:
    print('Skipping monkeypatch for pd.DataFrame.__del__: libc or malloc_trim() not found', file=sys.stderr)

제가 이 문제를 관리하기 위해 하는 일은 다음과 같습니다.

저는 큰 데이터 세트를 판다 데이터 프레임으로 읽어들여 api로 사용하는 작은 애플리케이션을 가지고 있습니다.그런 다음 사용자는 쿼리 매개 변수를 api로 전달하는 데이터 프레임을 쿼리할 수 있습니다.사용자가 여러 개의 데이터 세트를 읽었을 때 애플리케이션은 메모리 사용 제한에 직면하게 됩니다.

데이터 세트를 개별 데이터 프레임 변수로 읽는 대신 데이터 프레임 사전으로 읽습니다.

df_file_contents[file_name] = pd.read_csv(..)

사전을 지우기 위해 프런트 엔드에 api가 제공되었습니다.사전의 clear() 메서드를 호출합니다.sys.getsizeof(df_file_contents)가 특정 크기일 때 호출되도록 사용자 지정하거나 특정 키를 삭제하는 데 사용할 수 있습니다.

df_file_contents.clear()

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

반응형