2017-02-01 9 views
1

Кажется, что pandas запускает утечку памяти, когда iteritavely копирует значение из кадра данных.Утечка памяти при чтении значения из фрейма данных Pandas

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

В конце каждой итерации эти две переменные удаляются, а память, используемая текущим процессом, печатается (на каждые 1000 итераций). used memory increases!

Я думаю, что в какой-то момент может быть какая-то неявная копия (возможно, при чтении значения dataframe).

Быстрое исправление этой проблемы приводит к применению сборщика мусора на каждой итерации, но это довольно дорогое решение: процесс по меньшей мере в 10 раз медленнее.

Есть ли четкое объяснение причин возникновения этой проблемы?

import os, gc 
import psutil, pandas as pd 

N_ITER = 100000 
DF_SIZE = 10000 

# Define the DataFrame 
df = pd.DataFrame(index=range(DF_SIZE), columns=['my_col']) 
df['my_col'] = range(DF_SIZE) 


def memory_usage(): 
    """Return the memory usage of the current python process.""" 
    return psutil.Process(os.getpid()).memory_info().rss/1024 ** 2 


if __name__ == '__main__': 

    for i in range(N_ITER): 
     df_ind = pd.DataFrame(df.copy()) 
     val = df_ind.at[4242, 'my_col'] # The line that provokes the leak! 

     del df_ind, val # Useless 
     # gc.collect() # Garbage Collector prevents the leak but is slow 

     if (i % 1000) == 0: 
      print('Iter {}\t {} MB'.format(i, int(memory_usage()))) 
+0

Если вы звоните 'GC.Collect()' освобождает память, то это это совершенно нормальное и ожидаемое поведение. Есть некоторая круговая ссылка где-то мешает механизму ref-counting освободить память. Просто запустите свою программу; если слишком много невостребованных, претенциозных объектов накапливаются, GC автоматически запускается и очищает их. – user2357112

+0

Спасибо за ваш ответ. Я позволю запустить код, а затем подожду и посмотрю. Как вы могли бы предотвратить эти циркулярные ссылки? –

+0

Это должно быть сделано в реализации Pandas. – user2357112

ответ

1

Хорошо, кажется, что реальная боль происходит от того, df_ind создается.

Использование ссылки к оригинальному dataframe df, кажется, работает, но может быть немного рискованным, если мы намерены изменить df_ind.

Использование копий исходного информационного кадра df вызывает утечку памяти. Могут быть некоторые неявные копии бесполезных элементов от df. Эти скопированные элементы не принимаются кdel, , но их забираетgc.collect(). Это связано с затратами времени, так как эта операция требует времени.

Здесь перечислены различные попытки решить эту утечку памяти и их результаты:

df_ind = df     # Works! Dangerous since df could be modified 

df_ind = copy.copy(df)   # Works! Equivalent to df_ind = df 
df_ind = df.copy.deepcopy(df) # Fails. 

df_ind = df.copy(deep=False) # Works! Equivalent to df_ind = df 
df_ind = df.copy(deep=True) # Fails. 

Резюмируем:

  • Если вы хотите изменить временную dataframe, то дон 't использовать pandas. Вы можете использовать словари или заархивированные списки, чтобы получить то, что хотите.

  • Если вы не хотите изменять временную dataframe, то использование панд с явной опцией df_ind = df.copy(deep=False)

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

  • Нет связанных вопросов^_^