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

如何加速Pandas将大CSV分块写入Excel的处理速度?

CSV转XLSX大文件提速方案咨询与解决

问题背景

我需要将一个约100万行、177列的CSV文件通过分块方式追加写入单个XLSX文件完成格式转换,当前使用的代码如下:

import pandas as pd
import openpyxl
import timeit
import xlsxwriter
import os
import numpy as np

def process_csv_files(csv_file_path, excel_base_path, chunk_size):
    try:
        print(f'csv_file_path : {csv_file_path}')
        print(f'excel_base_path : {excel_base_path}')
        print(f'chunk_size : {chunk_size}')
        base_file_name, _ = os.path.splitext(os.path.basename(csv_file_path))
        excel_file_path = f'{base_file_name}.xlsx'
        excel_file_path = os.path.join(excel_base_path, excel_file_path)
        counter = 1
        if os.path.getsize(csv_file_path) > 0 :                                
            
            with pd.ExcelWriter(excel_file_path, engine='xlsxwriter') as writer:
                for i, chunk in enumerate(pd.read_csv(csv_file_path, chunksize=chunk_size, keep_default_na=False, na_filter=False, dtype=str)):
                    start_time = timeit.default_timer()                    
                    chunk.to_excel(writer, sheet_name='Sheet', index=False, startrow=i * chunk_size, header=False)
                    elapsed_time = timeit.default_timer() - start_time
                    print(f'writing chunk completed in {elapsed_time} seconds for chunk number : {counter} ')
                    counter += 1
                print(f'Successfully converted file : {csv_file_path}')
    except Exception as e:
        print('Error encountered in process_csv_files ' + str(e))

try:
    start_time_main = timeit.default_timer()
    output_base_path = 'output_directory_path'
    csv_file_path = '/input_directory_path/example.csv'
    chunk_size = 10000      
    process_csv_files(csv_file_path, output_base_path, chunk_size)
    elapsed_time = timeit.default_timer() - start_time_main
    print(f'Successfully converted the job in : {elapsed_time} seconds.')     
    
except Exception as e:
    print('Error encountered in csv_to_excel_convertor ' + str(e))

已尝试的优化措施

  • 调整最优分块大小(10000为最优值)
  • 更换XLSX写入引擎(xlsxwriter表现最佳)
  • 指定合适的数据类型(仅降低内存占用,写入耗时未改善)

当前单个分块(10000行×177列)处理耗时约13秒,求进一步提速方法。


提速方案建议

1. 启用xlsxwriter的constant_memory模式

xlsxwriter默认会为单元格添加默认格式,且缓存工作表数据,这会显著增加写入耗时。启用constant_memory模式可以跳过默认格式、逐行写入,大幅降低时间开销:

with pd.ExcelWriter(excel_file_path, engine='xlsxwriter', 
                    engine_kwargs={'options': {'constant_memory': True}}) as writer:

2. 绕过Pandas,直接用xlsxwriter写入数据

Pandas的to_excel封装会带来额外开销,直接将分块数据转为列表后调用xlsxwriter底层接口写入:

with pd.ExcelWriter(excel_file_path, engine='xlsxwriter') as writer:
    worksheet = writer.book.add_worksheet('Sheet')
    # 先写入表头
    header = pd.read_csv(csv_file_path, nrows=0).columns.tolist()
    worksheet.write_row(0, 0, header)
    start_row = 1
    counter = 1
    for chunk in pd.read_csv(csv_file_path, chunksize=chunk_size, keep_default_na=False, na_filter=False, dtype=str):
        start_time = timeit.default_timer()
        # 将分块转为二维列表
        data = chunk.values.tolist()
        # 批量写入行
        for row_num, row_data in enumerate(data, start=start_row):
            worksheet.write_row(row_num, 0, row_data)
        start_row += chunk_size
        elapsed_time = timeit.default_timer() - start_time
        print(f'写入分块 {counter} 耗时 {elapsed_time} 秒')
        counter += 1

3. 用原生csv模块读取,彻底跳过Pandas转换

如果不需要Pandas的数据处理能力,直接用csv模块读取文件,生成列表后写入xlsxwriter,能最大程度减少内存和时间开销:

import csv

with pd.ExcelWriter(excel_file_path, engine='xlsxwriter') as writer:
    worksheet = writer.book.add_worksheet('Sheet')
    with open(csv_file_path, 'r', encoding='utf-8') as f:
        reader = csv.reader(f)
        # 写入表头
        header = next(reader)
        worksheet.write_row(0, 0, header)
        start_row = 1
        counter = 1
        chunk = []
        for row in reader:
            chunk.append(row)
            if len(chunk) == chunk_size:
                start_time = timeit.default_timer()
                for idx, data_row in enumerate(chunk, start=start_row):
                    worksheet.write_row(idx, 0, data_row)
                elapsed_time = timeit.default_timer() - start_time
                print(f'写入分块 {counter} 耗时 {elapsed_time} 秒')
                counter += 1
                chunk = []
                start_row += chunk_size
        # 处理剩余行
        if chunk:
            for idx, data_row in enumerate(chunk, start=start_row):
                worksheet.write_row(idx, 0, data_row)

4. 多进程+临时文件合并(超大文件场景)

若CPU核心充足,可将分块写入拆分为多进程(注意xlsxwriter不支持多进程写同一个文件),先写入临时XLSX文件,最后用openpyxl合并:

from multiprocessing import Pool
import openpyxl

def process_chunk(chunk_data):
    chunk, temp_file, start_row = chunk_data
    with pd.ExcelWriter(temp_file, engine='xlsxwriter', engine_kwargs={'options': {'constant_memory': True}}) as writer:
        chunk.to_excel(writer, sheet_name='Sheet', index=False, startrow=start_row, header=False)
    return temp_file

# 主流程
temp_files = []
chunk_list = []
header = pd.read_csv(csv_file_path, nrows=0).columns.tolist()

for i, chunk in enumerate(pd.read_csv(csv_file_path, chunksize=chunk_size, keep_default_na=False, na_filter=False, dtype=str)):
    temp_file = f'temp_chunk_{i}.xlsx'
    chunk_list.append((chunk, temp_file, i*chunk_size))
    temp_files.append(temp_file)

# 多进程处理分块
with Pool(processes=os.cpu_count()) as pool:
    pool.map(process_chunk, chunk_list)

# 合并临时文件到最终文件
final_wb = openpyxl.Workbook()
final_ws = final_wb.active
final_ws.title = 'Sheet'
final_ws.append(header)

for temp_file in temp_files:
    wb = openpyxl.load_workbook(temp_file)
    ws = wb['Sheet']
    for row in ws.iter_rows(min_row=2, values_only=True):
        final_ws.append(row)
    wb.close()
    os.remove(temp_file)

final_wb.save(excel_file_path)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 14:38:16