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

如何加速DataFrame分析?20万行iterrows循环耗时过久求优化

高效优化20万行DataFrame时间区间求和方案

哇,20万行用iterrows()逐行处理确实会慢到离谱——我之前也踩过这个坑!问题的核心是你当前的写法是逐行遍历+全表筛选,时间复杂度达到了O(n²),20万行的话相当于要执行400亿次左右的操作,耗时几小时完全在意料之中。下面给你几个从易到难的高效优化方案,速度能提升几个数量级:

方案一:分组后组内矢量化处理(最推荐)

先按GROUP_ID分组,在每个组内完成时间区间的筛选和求和,这样可以把筛选范围从全表缩小到单个分组,再结合pandas的矢量化操作,效率会大幅提升:

import pandas as pd

def calculate_group_gaps(group):
    # 先对组内数据按BEG_DATE排序,后续区间匹配更高效
    group = group.sort_values('BEG_DATE', ignore_index=True)
    
    # 为每行创建时间区间:[THREE_YEAR_AGO, BEG_DATE]
    intervals = pd.IntervalIndex.from_arrays(
        group['THREE_YEAR_AGO'], 
        group['BEG_DATE'], 
        closed='both'  # 包含两端日期
    )
    
    # 用numpy广播快速匹配所有END_DATE是否在对应区间内
    end_dates = group['END_DATE'].values[:, None]
    # 生成布尔矩阵:行是原行,列是组内其他行,标记是否符合条件
    match_mask = intervals.contains(end_dates)
    
    # 矩阵乘法快速计算每行对应的GAP求和
    group['THREE_YR_GAPS'] = group['GAP'].values @ match_mask
    return group

# 应用到每个分组,禁用group_keys避免额外索引
df = df.groupby('GROUP_ID', group_keys=False).apply(calculate_group_gaps)

# 提取结果列表
three_yr_gaps = df['THREE_YR_GAPS'].tolist()

这个方案的优势是完全利用了pandas和numpy的矢量化优化,避免了Python层面的循环,单个分组内的操作都是C语言级别的速度。

方案二:自连接+分组聚合

如果对区间索引不太熟悉,也可以用自连接的方式实现:先把DataFrame按GROUP_ID自连接,筛选符合时间条件的行,再按原行索引聚合求和:

# 按GROUP_ID自连接,区分原表和连接表的列
merged = df.merge(df, on='GROUP_ID', suffixes=('', '_other'))

# 筛选时间条件:连接表的BEG_DATE >= 原表的THREE_YEAR_AGO,且连接表的END_DATE <= 原表的BEG_DATE
valid_mask = (merged['BEG_DATE_other'] >= merged['THREE_YEAR_AGO']) & (merged['END_DATE_other'] <= merged['BEG_DATE'])

# 按原行的索引分组,对符合条件的GAP求和
summed_gaps = merged[valid_mask].groupby(merged.index)['GAP_other'].sum()

# 把结果映射回原DataFrame,没有匹配项的填充0
df['THREE_YR_GAPS'] = summed_gaps.reindex(df.index, fill_value=0)

three_yr_gaps = df['THREE_YR_GAPS'].tolist()

这个方案逻辑更直观,但自连接会产生较多中间数据,如果你的分组数量很少、每个分组数据量很大,内存占用可能会比较高,适合分组较多的场景。

额外优化建议

  1. 确保日期列是datetime类型:如果你的BEG_DATE、END_DATE、THREE_YEAR_AGO是字符串类型,先转成datetime:
    df['BEG_DATE'] = pd.to_datetime(df['BEG_DATE'])
    df['END_DATE'] = pd.to_datetime(df['END_DATE'])
    df['THREE_YEAR_AGO'] = pd.to_datetime(df['THREE_YEAR_AGO'])
    
  2. 优化数据类型:把GROUP_ID设为category类型,减少内存占用和分组时间:
    df['GROUP_ID'] = df['GROUP_ID'].astype('category')
    
  3. 提前排序:对每个分组按日期排序后,后续的区间匹配或筛选会更高效,方案一中已经包含了这一步。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 07:31:43