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

合并10万文本文件并补全信息时Pandas迭代过慢,求优化方案

优化10万份文本文件合并与补全的Pandas方案

核心性能瓶颈分析

你当前代码的最大问题是每次循环调用pd.concat拼接DataFrame——concat每次都会创建新的内存对象,10万次迭代会产生巨量的内存拷贝开销,这是速度慢的主要原因。以下是针对性的优化方案:


优化方法与实现

1. 用列表暂存小DataFrame,最后一次性合并

放弃每次循环拼接,先将所有处理好的小DataFrame存入列表,循环结束后再执行一次concat,彻底消除频繁内存拷贝的开销。

import os
import pandas as pd

df_list = []  # 初始化列表暂存所有小DataFrame
resultsDir = "你的目标目录"

for root, dirs, files in os.walk(resultsDir):
    for file in files:
        if not file.endswith('.txt'):
            continue
        resultsFile = os.path.relpath(os.path.join(root, file))
        
        # 先判断文件是否存在且非空,避免无效IO
        if not os.path.isfile(resultsFile):
            print(f"文件 {resultsFile} 不存在")
            continue
        if os.path.getsize(resultsFile) == 0:
            # 直接创建带错误标记的空DataFrame
            empty_df = pd.DataFrame({'path': [resultsFile], 'resultsFile': [file], 'error': ["empty results file"]})
            df_list.append(empty_df)
            continue
        
        # 读取文件并解析路径字段
        df = pd.read_csv(resultsFile, delimiter='\t')
        df['path'] = resultsFile
        df['resultsFile'] = file
        pathLvls = resultsFile.split(os.sep)
        df['sdCard'] = pathLvls[-3][:5]
        df['site'] = pathLvls[-3][6:]
        df['capture'] = pathLvls[-4]
        df_list.append(df)

# 最后一次性合并所有DataFrame
df2 = pd.concat(df_list, ignore_index=True)

2. 多进程批量读取,加速IO操作

文件读取属于IO密集型任务,用多进程可以充分利用CPU资源,并行处理多个文件的读取与解析,大幅缩短总耗时。

import os
import pandas as pd
from concurrent.futures import ProcessPoolExecutor

def process_file(file_info):
    resultsFile, file = file_info
    # 重复文件判断与处理逻辑
    if not os.path.isfile(resultsFile):
        return pd.DataFrame({'path': [resultsFile], 'resultsFile': [file], 'error': ["file not found"]})
    if os.path.getsize(resultsFile) == 0:
        return pd.DataFrame({'path': [resultsFile], 'resultsFile': [file], 'error': ["empty results file"]})
    
    df = pd.read_csv(resultsFile, delimiter='\t')
    df['path'] = resultsFile
    df['resultsFile'] = file
    pathLvls = resultsFile.split(os.sep)
    df['sdCard'] = pathLvls[-3][:5]
    df['site'] = pathLvls[-3][6:]
    df['capture'] = pathLvls[-4]
    return df

# 先收集所有需要处理的文件信息
file_list = []
resultsDir = "你的目标目录"
for root, dirs, files in os.walk(resultsDir):
    for file in files:
        if file.endswith('.txt'):
            resultsFile = os.path.relpath(os.path.join(root, file))
            file_list.append((resultsFile, file))

# 多进程处理,进程数建议设为CPU核心数
with ProcessPoolExecutor(max_workers=os.cpu_count()) as executor:
    df_list = list(executor.map(process_file, file_list))

# 合并结果
df2 = pd.concat(df_list, ignore_index=True)

3. 优化pd.read_csv参数,降低内存占用

通过指定数据类型、跳过无用列等方式减少DataFrame的内存占用,间接提升处理速度:

  • 用dtype参数指定列的类型(比如dtype={'col1': 'int32', 'col2': 'float32'}),避免Pandas自动推断时占用多余内存
  • 用usecols指定需要读取的列,跳过不需要的字段
  • 若文件无表头,添加header=None参数

示例:

df = pd.read_csv(resultsFile, delimiter='\t', dtype={'sdCard': 'str', 'site': 'str'}, usecols=['需要的列名1', '需要的列名2'])

4. 提前解析路径字段,减少重复计算

可以在收集文件路径时就提前计算好sdCard、site、capture字段,避免每个文件处理时重复执行split操作:

file_list = []
resultsDir = "你的目标目录"
for root, dirs, files in os.walk(resultsDir):
    for file in files:
        if file.endswith('.txt'):
            resultsFile = os.path.relpath(os.path.join(root, file))
            pathLvls = resultsFile.split(os.sep)
            sdCard = pathLvls[-3][:5]
            site = pathLvls[-3][6:]
            capture = pathLvls[-4]
            # 将路径解析结果一起存入文件列表
            file_list.append((resultsFile, file, sdCard, site, capture))

之后在process_file函数中直接使用这些预计算的值,无需再次解析路径。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 20:35:02