内存问题将大量列表转换为数据框

时间:2020-10-30 14:10:54

标签: python pandas memory

我在一段代码的最后一行出现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'])

2 个答案:

答案 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=5length=1000000用于基准测试。报告了不同方法的峰值内存使用情况。基准测试在运行debian 10的Core i5-8250U(4C8T)64位笔记本电脑上执行。基准测试通过在tracemalloc.start()tracemalloc.get_traced_memory()之间插入解决方案代码来执行。

  • 此解决方案:148.825M <-获胜者
  • 发电机解决方案:288.355M
  • 原始解决方案:288.780M

可以看到使用生成器无济于事,这可能是因为在生成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