You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

循环处理千份大CSV性能衰减,求内存高效分块优化方案

优化方案:解决循环拼接DataFrame的性能下降问题

你的问题根源在于每次循环使用pd.concat拼接merged_data时,都会创建新的DataFrame并复制全部已有数据——随着数据量积累,内存占用越来越高,复制时间也会线性增长,这就是前50次快、后续越来越慢的原因。

下面是几个内存高效的处理方式:

1. 用列表暂存小DataFrame,最后一次性拼接

这是最直接的优化,避免每次循环复制大数据集:

import os
import pandas as pd

# 用列表暂存每个处理后的小DataFrame,而非每次拼接
data_list = []
count = 0

for index, row in df.iterrows():
    folder_name = row['File ID'].strip()
    file_name = row['File Name'].strip()
    file_path = os.path.join(root_path, folder_name, file_name)
    
    # 优化读取与转置步骤:直接指定index_col减少中间操作
    file_data = pd.read_csv(file_path, names=['Case', 'value'], sep='\t', index_col='Case')
    file_data_transposed = file_data.T.reset_index(drop=True)
    # 插入标识列
    file_data_transposed.insert(0, 'folder_file_id', f'{folder_name}_{file_name}')
    
    data_list.append(file_data_transposed)
    count += 1
    print(count)

# 最后一次性拼接所有数据
merged_data = pd.concat(data_list, axis=0, ignore_index=True)

这种方式内存效率高很多,因为列表只是存储每个小DataFrame的引用,直到最后一步才合并,不会在循环中反复复制大数据。

2. 分块保存到磁盘(超大数据量场景)

如果总数据量远超内存容量,可以每处理一定数量的文件就把当前数据保存到磁盘(优先用Parquet格式,比CSV压缩率高、读写快),最后再合并所有分块:

import os
import pandas as pd
from glob import glob

data_list = []
chunk_size = 50  # 每50个文件存一个分块
chunk_count = 0
root_path = "你的根路径"

count = 0
for index, row in df.iterrows():
    folder_name = row['File ID'].strip()
    file_name = row['File Name'].strip()
    file_path = os.path.join(root_path, folder_name, file_name)
    
    file_data = pd.read_csv(file_path, names=['Case', 'value'], sep='\t', index_col='Case')
    file_data_transposed = file_data.T.reset_index(drop=True)
    file_data_transposed.insert(0, 'folder_file_id', f'{folder_name}_{file_name}')
    
    data_list.append(file_data_transposed)
    count += 1
    print(count)
    
    # 达到chunk_size就保存分块
    if count % chunk_size == 0:
        chunk_count += 1
        chunk_df = pd.concat(data_list, axis=0, ignore_index=True)
        chunk_df.to_parquet(f'chunk_{chunk_count}.parquet')
        data_list = []  # 清空列表释放内存

# 处理剩余不足chunk_size的数据
if data_list:
    chunk_count += 1
    chunk_df = pd.concat(data_list, axis=0, ignore_index=True)
    chunk_df.to_parquet(f'chunk_{chunk_count}.parquet')

# 合并所有分块
chunk_files = glob('chunk_*.parquet')
merged_data = pd.concat([pd.read_parquet(f) for f in chunk_files], axis=0, ignore_index=True)

# 可选:删除临时分块文件
for f in chunk_files:
    os.remove(f)

额外优化点

  • 读取CSV时尽量减少不必要的操作:比如指定low_memory=False(如果数据类型复杂),或者用dtype提前指定列类型,避免pandas自动推断类型消耗资源。
  • 转置后的列名可以直接在读取时处理,减少后续插入操作的开销。

内容的提问来源于stack exchange,提问作者DeepLearner123

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 03:05:12