下面是一些代码,以便您可以准确地重现该问题。本质上,如果你不杀死它,它会在几秒钟内将你的内存从 90MB 左右爆炸到超过 5GB。随着内存消耗的增加,CPU 也会受到限制。
排序功能退出后,内存也会被保留。
如果我从一个大的主数据帧开始,将其切片然后进行排序,我似乎只会出现这个问题。如果我构建一堆独立的数据框;这不会发生。
def test_sorting(df_list):
counter = 0
total = len(df_list)
for i in range(0,total):
df_list[i].sort_index(inplace=True)
import pandas as pd
import numpy as np
from math import floor
def make_master_df(rows = 250000):
groups = 5
df = pd.DataFrame(np.random.randint(0,100,size=(rows, 26)), columns=list('ABCDEFGHIJKLMNOPQRSTUVWXYZ'))
df["timestep"] = pd.Series([floor(x / groups) for x in range(0,rows)])
df["id"] = pd.Series([ x % groups for x in range(0,rows)])
df = df.set_index(["timestep", "id"]).sort_index()
return df
def create_train_test_windows(df, train_size, test_size, slide_size, include_history = True, second_index=False):
n = train_size + test_size
size_multiplier = 1
if(second_index):
size_multiplier = df.index.levels[1].size
n = n * size_multiplier
list_df = None
if(include_history):
df.sort_index(ascending=True, inplace=True)
list_df = [df[:-(i + n)] for i in range(0, df.shape[0], slide_size * size_multiplier)]
list_df.insert(0,df[:])
list_df = list_df[::-1]
else:
raise Exception("excluding history currently not supported.")
list_df = [x for x in list_df if x.shape[0] >= n]
return list_df
master_df = make_master_df()
list_df = create_train_test_windows(master_df, 500, 20, 20, include_history=True, second_index=True)
这最终会在执行过程中耗尽你的内存,并且在执行结束后该内存将被保留。
test_sorting(list_df)
注释:
我注意到每个切片数据帧都维护第一个索引的完整索引级别大小(时间步长)。
我在每一步都强制使用 gc.collect() 只是为了尝试更激进。 (根本不起作用)。
我已经作为独立的 python 脚本和 IPython 笔记本进行了测试,结果相同。
我最好的猜测是,切片数据帧实际上不是一个正确的切片;他们随身携带了相当多的行李,这在其他地方有提到。
非常感谢任何见解/帮助!
最佳答案
我解决了这个问题。
在上面发布的代码中,我使用以下内容来创建我的数据框切片:
list_df = [df[:-(i + n)] for i in range(0, df.shape[0], slide_size * size_multiplier)]
这将返回对原始数据帧的引用,该数据帧被保留而不是“真实”副本。因此,当我排序时,它会引用所需的原始数据帧以及内存消耗激增的原因创建所有所需的索引。
为了解决这个问题,我现在使用以下方法来分割我的数据框:
list_df = [df[:-(i + n)].copy() for i in range(0, df.shape[0], slide_size * size_multiplier)]
.copy() 返回完整副本,不引用原始数据帧。
注意事项
使用 .copy() 选项,我的内存消耗达到 30GB,并且在排序过程中会飙升至 30.3GB 左右。我创建切片的执行时间稍微慢一些,但我的排序速度明显更快。
如果没有 .copy() 选项,我的起始大小约为 95MB,结束时约为 32GB。我的切片创建速度稍快,而排序速度却呈指数级下降。它还引入了一个潜在的警告,即根据我想要如何对每个切片进行排序以及我的切片重叠的事实,我可能会取消以前所做的工作。
总结如果您打算对较大数据帧的切片进行任何奇特的工作,从性能角度来看,使用以下命令从内存和 CPU 角度复制这些切片似乎要好得多切片上的 .copy() 运算符。
示例:
df[1:9].copy()
关于python - Pandas 内存泄漏和数据帧排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52086557/