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

读取5万份TXT后拼接Pandas DataFrame过慢,求优化方法

优化5万份TXT文件转Pandas DataFrame的方案

原代码的核心性能瓶颈有三个:循环中反复调用pd.concat导致大量内存拷贝、单线程处理未利用IO并行能力、read_fwf的固定宽度解析开销较高。以下是针对性的优化方案:

1. 避免循环concat,批量合并DataFrame

每次调用pd.concat都会创建新的DataFrame对象,5万次循环会产生巨量的内存碎片和拷贝开销。改为先收集所有小DataFrame到列表,最后一次性合并,能大幅降低时间消耗。

import glob
import pandas as pd

folder_path = '/drive/My Drive/dataset/train'
file_list = glob.glob(folder_path + "/*.txt")

def read_clean_df(file_name) -> pd.DataFrame:
    df = pd.read_fwf(file_name, header=None)
    df = df.drop(df.index[19])    
    df = df.T           
    df.columns = df.iloc[0]
    df = df[1:]
    df.reset_index(drop=True, inplace=True)
    return df

# 先收集所有文件的DataFrame到列表
df_collection = []
for file in file_list:
    df_collection.append(read_clean_df(file))

# 一次性合并所有DataFrame
train_df = pd.concat(df_collection, axis=0, ignore_index=True)
print(train_df.head(30))

2. 并行处理文件读取

文件读取属于IO密集型任务,单线程会等待IO操作完成后才处理下一个文件。用多线程并行处理可以同时读取多个文件,把等待IO的时间利用起来。

import glob
import pandas as pd
from concurrent.futures import ThreadPoolExecutor

folder_path = '/drive/My Drive/dataset/train'
file_list = glob.glob(folder_path + "/*.txt")

def read_clean_df(file_name) -> pd.DataFrame:
    df = pd.read_fwf(file_name, header=None)
    df = df.drop(df.index[19])    
    df = df.T           
    df.columns = df.iloc[0]
    df = df[1:]
    df.reset_index(drop=True, inplace=True)
    return df

# 用线程池并行处理,max_workers根据你的机器配置调整(建议8-16)
with ThreadPoolExecutor(max_workers=12) as executor:
    df_collection = list(executor.map(read_clean_df, file_list))

train_df = pd.concat(df_collection, axis=0, ignore_index=True)
print(train_df.head(30))

3. 替换read_fwf为手动文本解析

pd.read_fwf的固定宽度解析逻辑较重,如果你的TXT文件结构规则(比如每行是键值对),可以手动读取文本并处理,比调用read_fwf更快。假设你的文件每行是字段名+值的结构,示例如下:

import glob
import pandas as pd

folder_path = '/drive/My Drive/dataset/train'
file_list = glob.glob(folder_path + "/*.txt")

def read_clean_df(file_name) -> pd.DataFrame:
    # 读取文件并过滤空行
    with open(file_name, 'r', encoding='utf-8') as f:
        lines = [line.strip() for line in f if line.strip()]
    
    # 删除第19行(索引18,从0开始计数)
    del lines[18]
    
    # 拆分每行的键和值(适配空格分隔或固定宽度,这里以空格分隔为例)
    record = {}
    for line in lines:
        # 按第一个空格拆分键和值,避免值包含空格的情况
        key, value = line.split(maxsplit=1)
        record[key.strip()] = value.strip()
    
    # 返回单行DataFrame
    return pd.DataFrame([record])

# 结合并行处理使用效果最佳
from concurrent.futures import ThreadPoolExecutor
with ThreadPoolExecutor(max_workers=12) as executor:
    df_collection = list(executor.map(read_clean_df, file_list))

train_df = pd.concat(df_collection, axis=0, ignore_index=True)
print(train_df.head(30))

4. 指定数据类型减少内存占用

如果提前知道各字段的数据类型,在创建DataFrame时指定类型,可以大幅降低内存占用,进而提升合并和后续处理的速度。例如:

def read_clean_df(file_name) -> pd.DataFrame:
    # ... 前面的文本读取逻辑 ...
    # 预定义数据类型
    dtype_map = {
        'age': int,
        'score': float,
        'category': 'category'
    }
    return pd.DataFrame([record], dtype=dtype_map)

优化效果说明

  • 方案1+2结合,通常能把处理时间从小时级压缩到分钟级;
  • 方案3进一步优化单文件读取速度,适合结构规则的文本文件;
  • 方案4在数据量极大时能避免内存溢出问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 08:27:38