我在一段代码的最后一行出现out of memory
错误,该错误在for循环中创建了一个庞大的列表列表,然后将其转换为数据帧。
这是一个最小的可复制示例。我相信最后一行使用了很多额外的内存。如何使代码具有更高的内存效率?
import random, pandas, string
def function_to_generate_list():
def random_string():
return ''.join(random.choices(string.ascii_uppercase + string.digits, k = 50))
return [random_string(), random_string(), random.random()]
len = 10000*20000
df = []
for i in range(len):
df.append(function_to_generate_list())
df = pandas.DataFrame(df, columns=['column1', 'column2', 'column3'])
答案 0 :(得分:1)
最好的选择是以DataFrame容器使用的默认基础格式(即np.array
)预分配存储对象。这样,可以通过直接引用这些数组而不是对其进行转换后的副本来创建DataFrame,从而将内存占用量减少约一半。
import tracemalloc
import numpy as np
# provided function omitted
tracemalloc.start()
# preallocated output
arr1 = np.zeros(length, dtype=object)
arr2 = np.zeros(length, dtype=object)
arr3 = np.zeros(length, dtype=float)
# assign directly
for i in range(length):
arr1[i], arr2[i], arr3[i] = function_to_generate_list()
# make it a dataframe
df = pd.DataFrame(
{'column1': arr1, 'column2': arr2, 'column3': arr3}
)
print(f"===== Memory Footprint =====")
first, peak = tracemalloc.get_traced_memory()
print(f"Peak memory usage: {peak} ({peak/1048576:.3f}M)")
k=5
和length=1000000
用于基准测试。报告了不同方法的峰值内存使用情况。基准测试在运行debian 10的Core i5-8250U(4C8T)64位笔记本电脑上执行。基准测试通过在tracemalloc.start()
和tracemalloc.get_traced_memory()
之间插入解决方案代码来执行。
可以看到使用生成器无济于事,这可能是因为在生成DataFrame之前仍生成了中间非数组对象。
答案 1 :(得分:0)
考虑使用generators。
这样做df.append(function_to_generate_list())
时,实际上不需要一次存储所有值。创建数据框时,它只会对每个值进行一次迭代,因此一次只需要一个值。这就是发电机的作用。
您可以这样修改最后一行:
df = pandas.DataFrame((function_to_generate_list() for _ in range(length)),
columns=['column1', 'column2', 'column3'])
还要注意,我将len
重命名为length
。因为创建变量len
时会覆盖内置函数len
。