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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 08:57:22