Почему удаление столбцов или частей фрейма данных увеличивает использование памяти и как обеспечить сборку мусора на неиспользуемых фрагментах фрейма данных

#python #pandas #memory-management #garbage-collection #del

Вопрос:

При работе с большими кадрами данных вам необходимо быть осторожным с использованием памяти (например, вы можете загружать большие данные по частям, обрабатывать их и с этого момента удалять все ненужные части из памяти).

Я не могу найти никаких ресурсов по лучшим процедурам для работы со сбором мусора pandas , но я попробовал следующее и получил удивительные результаты:

 import os, psutil, gc
import pandas as pd

def get_process_mem_usage():
    process = psutil.Process(os.getpid())
    print("{:.3f} GB".format(process.memory_info().rss / 1e9))

get_process_mem_usage()
# Out: 0.146 GB
cdf = pd.DataFrame({i:np.random.rand(int(1e7)) for i in range(10)})
get_process_mem_usage()
# Out: 0.946 GB
 

Со следующим globals() и их использованием памяти:

           Size
cdf   781.25MB
_iii    1.05KB
_i1     1.05KB
_oh    240.00B
 

Когда я пытаюсь что-то удалить, я получаю:

 del cdf[1]
gc.collect()
get_process_mem_usage()
# Out: 1.668 GB
 

с высоким использованием памяти процесса, но следующее globals()

           Size
cdf   703.13MB
_i1     1.05KB
Out    240.00B
_oh    240.00B
 

таким образом, некоторая память все еще выделена, но не используется ни одним объектом globals() .

Я также видел странные результаты, когда делал что-то вроде

 cdf2 = cdf.iloc[:,:5]
del cdf
 

что иногда создает новый глобальный объект с таким именем "_5" и большим объемом использования памяти, чем cdf раньше (я не уверен , к чему относится этот глобальный объект, возможно, какой-то объект, содержащий столбцы, на которые больше нет ссылок cdf , но почему он больше?

Another option is to «delete» columns through one of:

 cdf = cdf.iloc[:, :5]
# or
cdf = cdf.drop(columns=[...])
 

где на столбцы больше не ссылается ни один объект, поэтому они удаляются. Но для меня это, похоже, происходит не каждый раз; Я мог бы поклясться, что видел, как мой процесс занимал одинаковый объем памяти после этой операции, даже когда я звонил gc.collect() позже. Хотя, когда я пытаюсь воссоздать это в блокноте, этого не происходит.

Так что, я думаю, мой вопрос таков:

  • Почему вышесказанное происходит при удалении, что приводит к большему использованию памяти
  • Каков наилучший способ гарантировать, что ненужные столбцы будут удалены из памяти и должным образом очищены от мусора?