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

如何将pandas iterrows循环改为向量化操作提升DataFrame性能

问题背景

已实例化全局作用域的报表DataFrame report_df,该对象派生自df_a,索引与df_a完全对齐,用于存储df_a和df_b两个DataFrame的对比结果。
当前对比逻辑通过iterrows逐行循环调度:

for idx, row in df_a.iterrows():
    compare(df_b, row, df_a_col, df_b_col, idx)

其中compare函数实现如下:

def compare(df_b, row, df_a_col, df_b_col, idx):
    matching_rows = df_b[df_b[df_b_col].astype(str) == str(row[df_a_col])]
    
    if len(matching_rows) > 0:
        # 仅取第一条匹配的行
        matching_row = matching_rows.head(1)
        # 标记当前行匹配成功
        report_df.loc[idx, "match"] = True

        # 仅当match_how为unmatched时更新匹配索引
        if report_df.at[report_df.index[idx], 'match_how'] == 'unmatched':
           report_df.loc[idx, "match_index"] = matching_row.index[0]

随着数据规模增长,逐行循环性能下降明显,需要改造为向量化流程提升运行效率。


解决方案

完全可以通过pandas内置的向量化操作替换逐行循环,核心是用C层级实现的哈希连接替代Python层逐行遍历,性能通常可以提升10~100倍,数据量越大优势越显著。

逻辑对齐说明

改造后的逻辑和原逐行实现100%对齐,核心规则保持一致:

  • 匹配时统一将两表的对比列转为字符串后做相等判断
  • 每一行df_a仅取df_b中第一条匹配的记录
  • 仅对匹配成功的行标记match=True,未匹配行保留原有字段值
  • 仅当report_df对应行的match_how值为unmatched时,才写入df_b匹配行的索引

实现代码

# 1. 预处理两表的匹配键,统一转为字符串避免类型误差
df_a_match_key = df_a[df_a_col].astype(str)
df_b_match_key = df_b[df_b_col].astype(str)

# 2. 构造临时表:df_b提前去重,每个匹配键仅保留第一条出现的记录,减少计算量
df_b_tmp = df_b.assign(
    __b_idx=df_b.index,
    __match_key=df_b_match_key
).drop_duplicates(subset="__match_key", keep="first")

# 3. 构造df_a临时表,绑定自身索引用于后续和report_df对齐
df_a_tmp = df_a.assign(
    __a_idx=df_a.index,
    __match_key=df_a_match_key
)

# 4. 左连接完成批量匹配,保留df_a所有行
match_res = df_a_tmp.merge(
    df_b_tmp[["__match_key", "__b_idx"]],
    on="__match_key",
    how="left"
).set_index("__a_idx")

# 5. 批量更新report_df字段
# 筛选出匹配成功的行
has_match_mask = match_res["__b_idx"].notna()
# 标记匹配成功状态
report_df.loc[has_match_mask, "match"] = True
# 筛选出需要更新match_index的行:匹配成功 且 match_how为unmatched
need_update_idx_mask = has_match_mask & (report_df["match_how"] == "unmatched")
# 批量写入匹配到的df_b索引
report_df.loc[need_update_idx_mask, "match_index"] = match_res.loc[need_update_idx_mask, "__b_idx"]

性能说明

原iterrows逐行循环属于Python层解释执行,每次循环都要对整个df_b做布尔筛选,时间复杂度为O(n*m)(n为df_a行数,m为df_b行数)。
上述向量化实现基于pandas内部优化的哈希连接逻辑,时间复杂度为O(n+m),百万行级数据集通常可以从几十分钟的运行时间压缩到数秒。如果内存足够,还可以通过将两表匹配键转为category类型进一步压缩内存、提升速度。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 19:30:09