2017-01-23 6 views
2

У меня возникли проблемы с пониманием того, почему Pandas Dataframes не очищаются из памяти должным образом. Я обнаружил это после того, как моя машина достигла 16 ГБ памяти, когда она должна была остаться около 400 Мб. Я создаю DataFrame, а затем создаю копию внутри той же функции. Эта функция оценивается много раз. Каждый раз, когда функция оценивается, увеличивается памяти - 337 Мб в этом примере ниже:Проблемы с памятью Pandas Dataframe

import pandas as pd 
import numpy as np 
from memory_profiler import profile 

@profile 
def loop_df(): 
    for _ in xrange(100): 
     copy_df() 

# Create a df and then copy it 
def copy_df(): 
    X = pd.DataFrame(np.random.rand(100000,10)) 
    X2 = X.loc[0:1000,:] 
    return 

loop_df() 

# Returns the following memory usage: 

#Line # Mem usage Increment Line Contents 
#================================================ 
# 13 100.3 MiB  0.0 MiB @profile 
# 14        def loop_df(): 
# 15 437.8 MiB 337.5 MiB  for _ in xrange(100): 
# 16 437.8 MiB  0.0 MiB   copy_df() 

Существуют различные темы, которые касаются в этом, но нет достойного решения: Memory leak using pandas dataframe, https://github.com/pandas-dev/pandas/issues/6046, https://github.com/pandas-dev/pandas/issues/2659, Pandas: where's the memory leak here?

Любые советы о том, что можно сделать, чтобы избежать этого, приветствуются. До сих пор использование сборщика мусора работало с простым примером, но сбой в моем сложном коде. Использование многопроцессорного пула также работало с моим сложным кодом. Однако было бы неплохо иметь решение, которое не предполагает использование модели многопроцессорности.

Может ли кто-нибудь объяснить, почему это происходит, когда объекты Python, такие как массивы и списки Numpy, не приводят к такому поведению? Это ошибка или предполагаемое поведение объектов DataFrame?

ответ

3

Использование del с последующим gc.collect(), кажется, сделать трюк:

import pandas as pd 
import numpy as np 
import gc 
from memory_profiler import profile 

@profile 
def loop_df(): 
    for _ in xrange(100): 
     copy_df() 

# Create a df and then copy it 
@profile 
def copy_df(): 
    X = pd.DataFrame(np.random.rand(100000,10)) 
    X2 = X.loc[0:1000,:] 
    del X, X2 
    gc.collect() 

loop_df() 

Тогда после этого, если вы все еще не хватает памяти, вот один из возможных решений с использованием Numpy memmap (отображены в карте памяти) структура данных :

import pandas as pd 
import numpy as np 
from memory_profiler import profile 
import gc 

@profile 
def loop_df(): 
    for _ in xrange(100): 
     copy_df() 
@profile 
def copy_df(): 
    mmap = np.memmap('mymemmap', dtype='float64', mode='w+', shape=(100000,10)) 
    mmap[:] = np.random.rand(100000,10) 
    df = pd.DataFrame(mmap) 
    df2 = df.loc[0:1000,:] 
    del df, df2, mmap 
    gc.collect() 
    pass 

if __name__ == '__main__': 
    loop_df() 

отображенные в память файлы используются для доступа небольших сегментов больших файлов на диске, не читая весь файл в память.

Извините, я не могу объяснить, почему ваш примерный код не освобождает данные pandas. Я подозреваю, что это имеет какое-то отношение к numpy и pandas, используя собственные массивы или что-то в этом роде.

Смежные вопросы