Pandas按日期和用户id统计累计已支付订单 低效代码优化求助
场景说明
需要统计每个订单的下单日期为止,对应客户的所有已支付订单数量。
- 输入数据样例:

- 预期输出效果:

原有实现代码运行效率极低,10万行数据需要运行10小时以上,原代码如下:
orders_paid,orders_inkasso = [] for y,row in df_dated_filt.iterrows(): x = x + 1 orders_paid.append(df_dated_filt[(df_dated_filt["order_id"] != row["order_id"]) & (df_dated_filt["m_order_paid"] == 1) & (df_dated_filt["customer_id"] == row["customer_id"]) & (pd.to_datetime(df_dated_filt['order_date'])<pd.to_datetime(row['order_date']))]["order_id"].count()) df_dated_filt["m_orders_paid"] = orders_paid
性能问题根源
- 使用
iterrows做行级遍历,本身性能远低于pandas向量化操作 - 每次循环都对全表做布尔筛选,时间复杂度为O(n²),数据量越大耗时增长越快
- 循环内重复执行
pd.to_datetime转换日期,产生大量无效计算
优化方案
用pandas分组排序+累计求和的向量化逻辑完全替代循环,时间复杂度降低到O(n log n),适配十万乃至百万级数据量:
import pandas as pd # 提前统一转换日期格式,仅执行一次 df_dated_filt['order_date'] = pd.to_datetime(df_dated_filt['order_date']) # 计算每个客户每个日期的已支付订单数 daily_paid = df_dated_filt.groupby(['customer_id', 'order_date'])['m_order_paid'].sum().reset_index(name='daily_cnt') # 按客户+日期排序 daily_paid = daily_paid.sort_values(['customer_id', 'order_date']) # 按客户分组,累计求和后向前移一位,空值填0,得到截止到前一天的累计已支付数 daily_paid['m_orders_paid'] = daily_paid.groupby('customer_id')['daily_cnt'].cumsum().shift(fill_value=0) # 把结果merge回原表 df_dated_filt = df_dated_filt.merge(daily_paid[['customer_id', 'order_date', 'm_orders_paid']], on=['customer_id', 'order_date'], how='left')
效果说明
10万行数据的计算耗时可以控制在100ms以内,性能提升超5个数量级,逻辑和原需求完全对齐,支持同一个客户同一天提交多笔订单的场景。
内容的提问来源于stack exchange,提问作者Ridvan Aydin Sibic
相关产品推荐
相关产品推荐

