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

如何用向量化替代groupby后的for循环加速Pandas代码?

问题

本人刚接触pandas、dataframe等工具。目前需处理展开后达数亿行的数据集,希望优化代码以提升运行效率。我通过.groupby('ORG_INDEX')得到数十万个分组,需对每个分组执行简单运算并新增列,但当前的for循环函数耗时过长。听闻向量化可替代for循环,但找不到适配的示例,现附上原函数:

def add_data_df(df1,df2):
  df1_group = df1.copy().groupby('ORG_INDEX', sort=False)
  sums=[]
  min_gfa=[]
  max_gfa=[]
  min_uni=[]
  max_uni=[]
  for group in df1_group:
    groupdf = group[1]
    sum_a = np.sum(groupdf['F_AREA'])
    sums.append(sum_a)

    groupdf['MINGFA'] = (groupdf['MIN_FLR'] * groupdf['F_AREA']) + (groupdf['MIN_FLR2'] * groupdf['F_AREA2'])
    groupdf['MAXGFA'] = (groupdf['MAX_FLR'] * groupdf['F_AREA']) + (groupdf['MAX_FLR2'] * groupdf['F_AREA2'])
    groupdf['MINUNITS'] = (groupdf['MIN_FLR'] * groupdf['UNITS_F']) + (groupdf['MIN_FLR2'] * groupdf['UNITS_F2'])
    groupdf['MAXUNITS'] = (groupdf['MAX_FLR'] * groupdf['UNITS_F']) + (groupdf['MAX_FLR2'] * groupdf['UNITS_F2'])

    min_gfa.append(np.sum(groupdf['MINGFA']))
    max_gfa.append(np.sum(groupdf['MAXGFA']))
    min_uni.append(np.sum(groupdf['MINUNITS']))
    max_uni.append(np.sum(groupdf['MAXUNITS']))

  df2['SUM_AREA']=sums
  df2['MIN_GFA']=min_gfa
  df2['MAX_GFA']=max_gfa
  df2['MIN_UNITS']=min_uni
  df2['MAX_UNITS']=max_uni

寻求将其改为向量化实现的方法。

向量化优化方案

原代码的核心问题是手动遍历分组,完全没利用pandas的向量化运算能力。以下是优化后的实现,全程用向量化操作替代循环,效率会提升几个数量级:

步骤1:计算中间列(逐行向量化运算)

四个中间列MINGFA、MAXGFA、MINUNITS、MAXUNITS的计算是逐行独立的,不需要分组,直接在原df1上计算即可:

# 直接在df1上计算中间列,无需分组
df1['MINGFA'] = df1['MIN_FLR'] * df1['F_AREA'] + df1['MIN_FLR2'] * df1['F_AREA2']
df1['MAXGFA'] = df1['MAX_FLR'] * df1['F_AREA'] + df1['MAX_FLR2'] * df1['F_AREA2']
df1['MINUNITS'] = df1['MIN_FLR'] * df1['UNITS_F'] + df1['MIN_FLR2'] * df1['UNITS_F2']
df1['MAXUNITS'] = df1['MAX_FLR'] * df1['UNITS_F'] + df1['MAX_FLR2'] * df1['UNITS_F2']

步骤2:分组聚合统计量

利用groupby.agg()一次性计算所有需要的聚合值,pandas会自动用向量化方式处理分组:

# 按ORG_INDEX分组,聚合所有需要的统计量
grouped_stats = df1.groupby('ORG_INDEX', sort=False).agg(
    SUM_AREA=('F_AREA', 'sum'),
    MIN_GFA=('MINGFA', 'sum'),
    MAX_GFA=('MAXGFA', 'sum'),
    MIN_UNITS=('MINUNITS', 'sum'),
    MAX_UNITS=('MAXUNITS', 'sum')
).reset_index(drop=True)  # 重置索引,确保和df2的行顺序匹配

步骤3:将聚合结果赋值给df2

直接把聚合后的DataFrame的列批量赋值给df2即可:

def add_data_df(df1, df2):
    # 若不想修改原df1,可先复制一份
    df1 = df1.copy()
    
    # 步骤1:计算中间列
    df1['MINGFA'] = df1['MIN_FLR'] * df1['F_AREA'] + df1['MIN_FLR2'] * df1['F_AREA2']
    df1['MAXGFA'] = df1['MAX_FLR'] * df1['F_AREA'] + df1['MAX_FLR2'] * df1['F_AREA2']
    df1['MINUNITS'] = df1['MIN_FLR'] * df1['UNITS_F'] + df1['MIN_FLR2'] * df1['UNITS_F2']
    df1['MAXUNITS'] = df1['MAX_FLR'] * df1['UNITS_F'] + df1['MAX_FLR2'] * df1['UNITS_F2']
    
    # 步骤2:分组聚合
    grouped_stats = df1.groupby('ORG_INDEX', sort=False).agg(
        SUM_AREA=('F_AREA', 'sum'),
        MIN_GFA=('MINGFA', 'sum'),
        MAX_GFA=('MAXGFA', 'sum'),
        MIN_UNITS=('MINUNITS', 'sum'),
        MAX_UNITS=('MAXUNITS', 'sum')
    ).reset_index(drop=True)
    
    # 步骤3:批量赋值给df2
    df2[['SUM_AREA', 'MIN_GFA', 'MAX_GFA', 'MIN_UNITS', 'MAX_UNITS']] = grouped_stats
    
    return df2

额外优化建议

  • 内存优化:若df1内存紧张,计算完中间列后可直接聚合,再删除中间列释放内存:df1.drop(['MINGFA', 'MAXGFA', 'MINUNITS', 'MAXUNITS'], axis=1, inplace=True)。
  • 顺序一致性:因为设置了sort=False,分组结果的顺序和df1中ORG_INDEX首次出现的顺序一致,确保df2的行顺序与之对应即可避免赋值错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 19:22:43