Pandas:如何高效抵消商品销售与退货行并保留剩余行?
高效解决商品销售与退货抵消问题
针对大数据集的这类需求,apply()逐行处理的效率确实很低,我们可以根据你的具体抵消逻辑选择不同的高效矢量化方案:
情况1:完全抵消的商品组直接移除(即商品总销售-退货数量为0时,所有相关行都删除)
如果你的需求是:当某个商品的所有销售和退货数量总和为0时,移除该商品的所有行;总和不为0则保留所有行,可以用完全矢量化的分组聚合+过滤操作,这是效率最高的方式,适合超大数据集:
import pandas as pd # 示例数据集 df = pd.DataFrame({ 'id': [0, 1, 2, 3], 'product_id': ['A', 'B', 'A', 'B'], 'item_count': [2, 3, -2, 1] }) # 计算每个商品的总数量(用transform保证和原数据行数一致) product_total = df.groupby('product_id')['item_count'].transform('sum') # 过滤掉总数量为0的商品行 filtered_df = df[product_total != 0]
运行后filtered_df会保留id1和id3的行,完全符合你的示例需求,这种方法避免了任何逐行操作,性能比apply()提升几个数量级。
情况2:部分抵消后保留剩余数量的行(如销售+3、退货-2,最终保留销售+1的行)
如果需要更精细的抵消(逐行匹配销售和退货,直到一方数量耗尽),可以用分组后的累计计算+合并操作,同样避免逐行apply():
def process_product_group(group): # 分离销售和退货,排序保证处理顺序(可根据业务调整排序键,比如时间) sales = group[group['item_count'] > 0].copy().sort_values('id') returns = group[group['item_count'] < 0].copy().sort_values('id') if sales.empty or returns.empty: return group # 转换退货为正值,计算累计量 returns['abs_count'] = returns['item_count'].abs() sales['cum_sales'] = sales['item_count'].cumsum() returns['cum_returns'] = returns['abs_count'].cumsum() # 用merge_asof匹配累计量,找到抵消点 merged = pd.merge_asof(sales, returns, left_on='cum_sales', right_on='cum_returns', direction='forward') # 处理完全抵消的销售行 sales['remaining'] = sales['cum_sales'] - merged['cum_returns'].fillna(0) sales.loc[sales['remaining'] <= 0, 'item_count'] = 0 # 处理完全抵消的退货行 returns['remaining'] = merged['cum_sales'].fillna(0) - returns['cum_returns'] returns.loc[returns['remaining'] >= 0, 'item_count'] = 0 # 合并剩余行并过滤掉数量为0的行 remaining = pd.concat([sales, returns]) remaining = remaining[remaining['item_count'] != 0] # 恢复退货的负号(如果有剩余) remaining.loc[remaining['item_count'] < 0, 'item_count'] = -remaining['abs_count'].fillna(remaining['item_count'].abs()) return remaining[group.columns] # 分组处理,这里的apply是按组处理而非逐行,效率比逐行apply高很多 result_df = df.groupby('product_id').apply(process_product_group).reset_index(drop=True)
这种方法虽然用到了groupby().apply(),但它是按商品组批量处理,而非逐行迭代,在大数据集上的性能依然远优于逐行apply()。
性能小贴士
- 优先选择情况1的矢量化方案,它的时间复杂度是O(n),是处理大数据集的最优解;
- 如果必须用情况2的精细抵消,建议先对数据按
product_id排序,能提升分组和合并操作的效率; - 避免在循环或逐行操作中处理数据,Pandas的矢量化操作和分组聚合是为大数据集优化过的。
内容的提问来源于stack exchange,提问作者E-Kami
相关产品推荐
相关产品推荐

