大型列表列表转DataFrame内存不足问题的优化方案咨询
嘿,这个内存问题我太熟了——你现在的做法是先把所有数据都塞进一个大列表里,再转成DataFrame,这相当于把整个数据集在内存里存了两份,难怪会爆内存!下面给你几个针对性的优化方案,按易实现程度排序:
优化方案一:用生成器替代列表存储
列表会一次性把所有元素加载到内存,而生成器是按需生成数据,不会提前占用大量内存。直接把循环改成生成器表达式传给DataFrame构造器就行:
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当变量名!会覆盖Python内置的len()函数 total_rows = 10000 * 20000 # 用生成器表达式(...)替代列表推导式[...],DataFrame可以直接迭代生成器 df = pandas.DataFrame( (function_to_generate_list() for _ in range(total_rows)), columns=['column1', 'column2', 'column3'] )
这样内存里只会同时存在当前生成的一行数据,而不是整个百万级的列表,内存占用能砍一半以上。
优化方案二:分块写入/处理
如果数据集实在大到生成器都扛不住,那就分批次生成数据,写完一批就释放内存,甚至直接写入文件(比如CSV),后续再按需读取:
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()] total_rows = 10000 * 20000 chunk_size = 100000 # 每次生成10万行,可根据内存调整 csv_path = 'large_dataset.csv' first_write = True for start in range(0, total_rows, chunk_size): end = min(start + chunk_size, total_rows) # 生成当前块的数据 chunk_data = [function_to_generate_list() for _ in range(end - start)] chunk_df = pandas.DataFrame(chunk_data, columns=['column1', 'column2', 'column3']) # 写入CSV:第一次写表头,后续追加 chunk_df.to_csv( csv_path, mode='w' if first_write else 'a', header=first_write, index=False ) # 手动释放内存(Python GC也会处理,但主动释放更稳妥) del chunk_data, chunk_df first_write = False # 后续需要分析时再读取,还可以指定dtype进一步省内存 df = pandas.read_csv(csv_path, dtype={'column1': 'string', 'column2': 'string', 'column3': 'float32'})
这种方式每次内存里只存一个小块的数据,完全不会出现内存溢出的问题。
优化方案三:指定紧凑数据类型减少内存占用
默认情况下,pandas会给字符串列分配object dtype(每个元素都是指针),给浮点数分配float64,这些类型都比较占内存。我们可以手动指定更紧凑的类型:
# 结合生成器和指定类型,双重优化 df = pandas.DataFrame( (function_to_generate_list() for _ in range(total_rows)), columns=['column1', 'column2', 'column3'], dtype={ 'column1': 'string', # 用pandas的StringDtype替代object,内存更高效 'column2': 'string', 'column3': 'float32' # 浮点数从64位降到32位,内存减半,精度对大部分场景足够 } )
StringDtype是矢量化存储字符串,比object dtype节省30%-50%的内存;float32比float64直接少用一半内存,效果非常明显。
额外小提醒
你原来的代码里用len当变量名,这会覆盖Python内置的len()函数,后续如果调用len()会报错,一定要改成别的名字(比如上面的total_rows)!
内容的提问来源于stack exchange,提问作者user5054
相关产品推荐
相关产品推荐

