Python 将大量列表转换为数据帧时出现内存问题

Python 将大量列表转换为数据帧时出现内存问题,python,pandas,memory,Python,Pandas,Memory,我在一段代码的最后一行出现内存不足错误,这段代码在for循环中创建了一个巨大的列表,然后将其转换为数据帧 这是一个最小的可重复的例子。我相信在最后一行中使用了很多额外的内存。如何提高代码的内存效率 import random, pandas, string def function_to_generate_list(): def random_string(): return ''.join(random.choices(string.ascii_uppercase +

我在一段代码的最后一行出现
内存不足
错误,这段代码在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'])
考虑使用

执行此操作时,
df.append(函数\u to \u generate\u list())
实际上不需要一次存储所有值。当您创建一个dataframe时,它只会在每个值上迭代一次,所以一次只需要一个值。这就是发电机的作用

您可以这样修改最后一行:

df = pandas.DataFrame((function_to_generate_list() for _ in range(length)), 
                      columns=['column1', 'column2', 'column3'])

还要注意,我将
len
重命名为
length
。因为当您创建变量
len
时,您会覆盖一个内置函数
len

,最好的选择是以数据帧容器使用的默认底层格式(即
np.array
)预分配存储对象。通过这种方式,可以通过直接引用这些阵列来创建数据帧,而不是制作它们的转换副本,从而将内存占用减少大约一半

解决方案 基准 基准测试中使用了
k=5
length=1000000
。报告了不同方法的峰值内存使用情况。该基准测试在运行debian 10的Core i5-8250U(4C8T)64位笔记本电脑上执行。通过在
tracemaloc.start()
tracemaloc.get\u tracked\u memory()
之间插入解决方案代码来执行基准测试


  • 此解决方案:148.825M谢谢@go2nirvana!我对发电机不熟悉。只需将最后四行更改为您上面所写的内容就足够了,或者我是否应该在
    函数\u到生成\u列表
    定义中进行更改(例如将
    返回
    替换为
    收益
    )?此答案不会减少内存占用,因为仍需创建中间非数组对象。看看我的答案,谢谢你,黄比尔!在实际情况中,我知道
    长度的上限,但不知道到底要填充多少。换句话说,在调用
    函数\u生成\u list()
    之前有一个if条件。在这种情况下,我想我仍然可以得到大小为
    长度
    的数组,并且在创建数据帧后
    删除
    未填充的行?或者有更好的方法吗?我不认为会有一个强有力的解决办法,因为总是有机会达到理论上限。您唯一能做的就是为对象找到更多可用空间。例如,用于将输出阵列存储在硬盘上。我明白了,谢谢。我有足够的空间来处理上限被命中的情况,但是我必须删除未填充的行,因为这些行不应该包含在最终的数据帧中。所以我的最后一个问题是关于
    drop
    操作是否有效。如果我通过调用
    df.drop(df.index[df.column1==0],inplace=True)执行就地
    drop
    操作来删除未填充的行,这不会增加大量内存使用,对吗?我的意思是,数据帧在
    删除过程中不会被复制到任何地方
    ?我认为这已经是另一个问题了,因为实现可能必须根据这些附加信息进行调整。您可以发布一个单独的后续问题。
    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)")