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

Pandas遍历1.5万行DataFrame过慢问题优化求助

问题描述

我从Excel文件读取了一个包含15000条记录、20列的pandas DataFrame,使用以下代码读取耗时约4.13秒,当前pandas版本为2.0.2。

df = pd.read_excel(excel_path, sheet_name='Sheet 1', header=[2, 3]).astype(object).replace(np.nan, 'None')

我通过for循环遍历df.iloc,将每行数据转换为键名自定义的字典并组成列表,示例代码如下:

data = []
for i in df.iloc:
    mydict = {}
    mydict['col1'] = i['Column 1 Name'].values[0]
    mydict['col2'] = i['Column 2 Name'].values[0]

    mydict['doc_date'] = datetime.datetime.strftime(i['Doc Details']['Doc Date'], r'%d-%m-%Y') \
        if isinstance(i['Doc Details']['Doc Date'], datetime.datetime) \
        else i['Doc Details']['Doc Date'].replace('/', '-')


    # 17 more columns

    data.append(mydict)

该循环耗时约72秒,仅涉及键名修改和日期格式处理,无其他复杂逻辑。

请问:

  1. 如何更快地遍历DataFrame并生成指定格式的字典列表?
  2. 为何pandas读取同等数据仅需4秒,而遍历却耗时72秒?

注:需保留「每行对应一个字典、键名自定义」的输出格式,不能修改前后端交互契约。


解答

1. 提速遍历生成字典列表的方法

方法一:矢量化预处理+批量转字典

先对所有列做批量处理(重命名、日期格式化),再直接转字典列表,这是效率最高的方式:

import pandas as pd
import datetime

# 定义原多级列名到自定义键名的映射
col_mapping = {
    ('Column 1 Name', ''): 'col1',
    ('Column 2 Name', ''): 'col2',
    ('Doc Details', 'Doc Date'): 'doc_date',
    # 补充剩余17列的映射关系
}

# 重命名列
df_renamed = df.rename(columns=col_mapping)

# 批量格式化日期列
def format_date(x):
    if isinstance(x, datetime.datetime):
        return x.strftime('%d-%m-%Y')
    elif isinstance(x, str):
        return x.replace('/', '-')
    return x  # 兼容异常数据

df_renamed['doc_date'] = df_renamed['doc_date'].apply(format_date)

# 直接转成字典列表,orient='records'会按行生成字典
data = df_renamed.to_dict(orient='records')

方法二:用itertuples替代iloc遍历

如果必须保留逐行处理逻辑,itertuples返回的是轻量命名元组,访问开销远低于iloc生成的Series:

data = []
# index=False跳过行索引,只返回数据列
for row in df.itertuples(index=False):
    mydict = {}
    # 按列的位置取值(对应原多级索引的列顺序)
    mydict['col1'] = row[0]
    mydict['col2'] = row[1]
    
    # 处理日期:假设原('Doc Details', 'Doc Date')是第n列
    doc_date_val = row[n]
    if isinstance(doc_date_val, datetime.datetime):
        mydict['doc_date'] = doc_date_val.strftime('%d-%m-%Y')
    else:
        mydict['doc_date'] = doc_date_val.replace('/', '-')
    
    # 补充其他列的赋值逻辑
    data.append(mydict)

方法三:用swifter自动优化apply(可选)

如果部分列需要复杂自定义处理,swifter会自动选择矢量化或并行apply的最优方式:

import swifter

df_renamed['doc_date'] = df_renamed['doc_date'].swifter.apply(format_date)
data = df_renamed.to_dict(orient='records')

2. 读取与遍历耗时差异的原因

  • 底层实现差异:pd.read_excel依赖的openpyxl/xlrd库大部分逻辑是C/C++实现的矢量化批量操作,避开了Python解释器的循环开销;而你的逐行遍历完全在Python层面执行,每次迭代都要创建Series对象、处理多级索引取值,15000次循环的累计开销极大。
  • 数据类型影响:读取时用.astype(object)把所有列转为object类型,让pandas失去了对数值、日期类型的矢量化优化能力,逐行访问时的类型检查、转换开销进一步放大。
  • 操作粒度差异:读取是一次性批量加载解析数据,而遍历是逐行做零散的键值赋值和格式转换,单步操作的重复开销被多次循环放大。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 19:28:14