如何高效实现DataFrame自连接?计算经销商过往5条销售车辆总数
优化计算经销商过去5条销售记录车辆总数的高效方法
需求说明
需要计算数据集中每个经销商每条销售条目对应的过去5条销售记录的车辆总数,当前采用自连接的实现方式在大数据集下效率极低,寻求更优方案。
当前实现及问题
当前实现步骤:
- 为每个销售条目按经销商分组计算行号
- 自连接获取经销商历史销售数据
- 筛选当前条目之前的5条记录并求和
代码如下:
# Calculate row number for each sale df = df.sort_values(["dealership_id", "time"], ascending=[True, True]) df["row_num"] = df.groupby(["dealership_id"]).cumcount() df.drop_duplicates() df_2 = df[["dealership_id", "sales_entry", "car_count", "row_num"]] # Join to get history df_3 = pd.merge( df_2[['dealership_id','sales_entry','row_num']], df_2[['dealership_id','car_count','row_num']], how="inner", on=["dealership_id"], ) # Keep past 5 sales df_4 = df_3.loc[(df_3['row_num_x'] - df_3['row_num_y'] > 0) & (df_3['row_num_y'] - df_3['row_num_x'] <= 4)] # Sum 5 previous sales df_4 = ( df_4.groupby(["dealership_id", "sales_entry"]) .agg({"car_count": "sum"}) .reset_index() )
核心问题:自连接会为每个经销商的每条记录生成与所有同经销商记录的组合,当数据集规模较大时,中间表df_3会呈指数级膨胀,严重消耗内存和计算资源,导致效率极低。
优化方案:使用滚动窗口(Rolling Window)
利用Pandas的rolling窗口功能,按经销商分组后直接计算每条记录之前的5条数据总和,无需自连接,效率大幅提升。
优化步骤:
- 按
dealership_id和time排序,确保数据按经销商的销售时间顺序排列 - 按经销商分组,对
car_count应用滚动窗口求和,窗口大小设为5,且仅包含当前记录之前的历史数据(不包含当前行) - 处理不足5条历史记录的情况(自动取所有已有历史数据求和)
优化代码:
# 1. 按经销商和时间排序 df = df.sort_values(["dealership_id", "time"], ascending=[True, True]) # 2. 按经销商分组,计算过去5条记录的车辆总数(不包含当前条) df['prev_5_cars_sum'] = df.groupby('dealership_id')['car_count'].rolling( window=5, # 窗口大小为5 closed='left', # 窗口不包含当前行(仅取之前的记录) min_periods=0 # 不足5条时取所有已有记录求和 ).sum().reset_index(level=0, drop=True) # 可选:保留需要的列 result = df[["dealership_id", "sales_entry", "prev_5_cars_sum"]]
关于尝试的错误说明
你尝试的df_3['dealership_id'][df_3['dealership_id']].values写法有误,这是试图用列值作为索引去取值,但df_3的索引不是dealership_id,所以会提示索引不存在。这种写法本身也无法替代自连接的逻辑,不建议使用。
数据集示例
dealership_id sales_entry car_count time row_num 0 123 entry_asfs 3 11:00 1 1 123 entry_kmsl 0 13:05 2 2 456 entry_sdfm 2 14:10 3 3 456 entry_sknw 1 10:10 1 4 456 entry_kmsl 1 14:35 2
内容的提问来源于stack exchange,提问作者C L
相关产品推荐
相关产品推荐

