Python顺序处理多文件时内存溢出问题及解决方案咨询
解决大数据合并时的内存溢出问题
我完全懂你现在的痛点——明明已经把大文件拆成了小份,处理第一个文件还好好的,到第二个就内存爆了,用了del和gc.collect()也没见效,直接卡得Jupyter动不了。下面给你几个针对性的解决方案,你可以从易到难逐一尝试:
1. 先搞定最浪费内存的重复加载问题
你现在每次调用merge_data都会重新读一遍db1.csv和db2.csv,这完全是没必要的重复操作!这两个文件是静态的,只需要加载一次就行,重复读取会平白占用大量内存,这应该是导致你内存撑爆的核心原因之一。
修改代码如下:
# 把静态数据移到函数外面,只加载一次 db1 = pd.read_csv('../data/db1.csv') db2 = pd.read_csv('../data/db2.csv') def merge_data(path): temp = pd.read_csv(path) temp = pd.merge(temp, db1, on='db1_id', how='left') temp = pd.merge(temp, db2, on='db2_id', how='left') return temp.drop('target', axis=1), temp['target']
这个改动最小,但效果绝对立竿见影。
2. 给内存释放加上“强制保险”
有时候del变量后,Python的垃圾回收不会立刻生效,尤其是Jupyter环境会悄悄保留变量的历史引用,导致内存没真正释放。你可以在循环里试试这套组合拳:
import gc for f in files_list: Xdf, ydf = merge_data(f) # 这里写你的Xdf、ydf处理逻辑 # 处理完立刻清理,别等 del Xdf, ydf # 强制触发垃圾回收,并且等待回收完成 gc.collect() # 针对Jupyter的专属操作:清除变量的历史引用 %reset_selective -f Xdf ydf
%reset_selective是Jupyter的魔法命令,能直接干掉指定变量的所有引用,避免Jupyter偷偷占着内存不放。
3. 给数据“瘦身”:优化读取和存储类型
合并后每条记录有3000列,很多列可能根本不需要,或者可以用更紧凑的类型存储:
- 读取时只拿需要的列:如果子文件里只有
db1_id、db2_id和target是必须的,其他列直接跳过:temp = pd.read_csv(path, usecols=['db1_id', 'db2_id', 'target']) - 压缩静态数据的类型:检查
db1和db2的列,把字符串列转成category类型(如果重复值多),把整数列转成更小的数值类型(比如int64转int32,只要数值范围够):# 把重复多的字符串列转成category db1['category_col'] = db1['category_col'].astype('category') # 自动把整数列压缩到最小合适类型 db1['int_col'] = pd.to_numeric(db1['int_col'], downcast='integer')
这一步能大幅降低静态数据的内存占用。
4. 给单个子文件再分块
如果10万条记录合并后还是占内存,那就把单个子文件再拆成更小的块处理:
def merge_data(path): # 每次读1万条,可根据内存情况调整chunksize chunks = pd.read_csv(path, chunksize=10000) X_list = [] y_list = [] for chunk in chunks: chunk = pd.merge(chunk, db1, on='db1_id', how='left') chunk = pd.merge(chunk, db2, on='db2_id', how='left') X_list.append(chunk.drop('target', axis=1)) y_list.append(chunk['target']) # 合并所有小块 Xdf = pd.concat(X_list, ignore_index=True) ydf = pd.concat(y_list, ignore_index=True) return Xdf, ydf
这样每次只处理1万条数据的合并,内存压力会小很多。
5. 换用更适合大数据的工具
如果Pandas实在顶不住,可以试试专门处理超大数据的库:
- Dask:用法和Pandas几乎一致,会自动分块处理超出内存的数据,支持并行计算。
- Vaex:用内存映射技术读取数据,不需要把整个数据集加载到内存,适合处理亿级别的数据。
比如用Dask的示例代码:
import dask.dataframe as dd # 用Dask读取静态数据 db1 = dd.read_csv('../data/db1.csv') db2 = dd.read_csv('../data/db2.csv') for f in files_list: temp = dd.read_csv(f) temp = temp.merge(db1, on='db1_id', how='left') temp = temp.merge(db2, on='db2_id', how='left') Xdf = temp.drop('target', axis=1) ydf = temp['target'] # 直接写入文件,不要把数据留在内存里 Xdf.to_csv(f'processed_X_{f}.csv', single_file=True) ydf.to_csv(f'processed_y_{f}.csv', single_file=True)
建议你先从第1、2点开始尝试,这两个改动最小,见效最快。
内容的提问来源于stack exchange,提问作者Hossein
相关产品推荐
相关产品推荐

