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

嵌套循环处理两个大数据框匹配计数性能优化求助

优化方案

核心问题分析

嵌套iterrows()循环的时间复杂度为O(M*N)(M=330万,N=40万),总计算量达1.32e12次,完全无法在合理时间内完成。同时iterrows()返回行副本,原代码中修改row['PromoCount']不会实际更新DataFrame,这是一个隐藏bug。

优化方案1:Merge+分组统计(推荐,性能最优)

利用Pandas向量化合并与分组操作,将时间复杂度降至O(M+N)级别:

步骤1:统一日期格式为datetime

import pandas as pd

# 转换日期列(若当前为字符串类型)
SalesDF['SalesDays'] = pd.to_datetime(SalesDF['SalesDays'])
SfPromos['Start date'] = pd.to_datetime(SfPromos['Start date'])
SfPromos['End date'] = pd.to_datetime(SfPromos['End date'])

步骤2:合并表并筛选有效匹配

# 基于商品编码合并两个表,保留SalesDF所有行
merged = pd.merge(
    SalesDF[['article', 'SalesDays']],
    SfPromos[['Item Code', 'Start date', 'End date']],
    left_on='article',
    right_on='Item Code',
    how='left'
)

# 筛选销售日期落在促销区间内的行
valid_matches = merged[
    (merged['SalesDays'] >= merged['Start date']) & 
    (merged['SalesDays'] <= merged['End date'])
]

步骤3:统计每行的促销次数

# 按SalesDF原始索引分组,统计匹配次数
promo_counts = valid_matches.groupby(valid_matches.index).size()

# 赋值到PromoCount列,无匹配的行填充0
SalesDF['PromoCount'] = promo_counts.reindex(SalesDF.index, fill_value=0)

优化方案2:分组区间匹配(内存占用更低)

若Merge操作内存压力大,可按商品编码分组,针对每个商品的促销区间单独匹配:

步骤1:构建商品-促销区间字典

# 按Item Code分组,生成每个商品的促销区间索引
promo_dict = SfPromos.groupby('Item Code').apply(
    lambda x: pd.IntervalIndex.from_arrays(x['Start date'], x['End date'], closed='both')
).to_dict()

步骤2:计算每行促销次数

# 定义函数计算单一行的促销次数
def count_promos(row):
    intervals = promo_dict.get(row['article'], pd.IntervalIndex([]))
    return intervals.contains(row['SalesDays']).sum()

# 用apply计算(比嵌套循环快100+倍,性能略逊于方案1)
SalesDF['PromoCount'] = SalesDF.apply(count_promos, axis=1)

额外性能建议

  • 确保article和Item Code列是字符串/整数类型,避免混合类型拖慢匹配效率。
  • 若内存不足,可按article分组后分批处理,再合并结果。
  • 禁用链式赋值,所有操作采用明确赋值方式。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 23:02:41