如何用Python按连续销售天数区间统计产品销量?
解决按产品统计连续销售天数区间总销量的问题
你之前的代码误区在于把**每月的日期数值(比如1号、2号)**当成了连续销售天数,完全没捕捉到「连续销售的时间段」这个核心需求。咱们来一步步修正,用pandas实现正确的统计逻辑:
核心思路
要实现需求,关键是先给每个产品的销售记录划分「连续销售的日期块」,再计算每个块的天数,最后把这些块归类到对应的天数区间并汇总销量。
完整代码实现
import pandas as pd # 假设你的数据集已经加载为DataFrame df # 第一步:标准化日期格式并排序 df["DATE_LOCATION"] = pd.to_datetime(df["DATE_LOCATION"], format="%d-%m-%y %H:%M") df = df.sort_values(["PRODUCT_ID", "DATE_LOCATION"]) # 第二步:识别每个产品的连续销售日期块 # 计算当前日期与同组前一个日期的天数差 df["date_diff"] = df.groupby("PRODUCT_ID")["DATE_LOCATION"].diff().dt.days # 用cumsum生成连续块的标识:差值≠1时,视为新块的开始 df["continuous_block"] = df.groupby("PRODUCT_ID")["date_diff"].apply(lambda x: (x != 1).cumsum()) # 第三步:统计每个连续块的销售天数和总销量 block_summary = df.groupby(["PRODUCT_ID", "continuous_block"]).agg( block_days=("DATE_LOCATION", "nunique"), # 每个块的连续销售天数(去重,避免同一天多条记录) total_sold=("Sold", "sum") ).reset_index() # 第四步:将连续天数映射到指定区间 def map_to_day_range(days): if 1 <= days <= 3: return "1-3" elif 4 <= days <= 7: return "4-7" elif 8 <= days <= 15: return "8-15" elif days >= 16: return ">16" return None # 无意义分支,仅做兜底 block_summary["Days"] = block_summary["block_days"].apply(map_to_day_range) # 第五步:按产品和区间汇总销量,整理成期望格式 final_result = block_summary.groupby(["PRODUCT_ID", "Days"])["total_sold"].sum() # 转成宽表,填充缺失区间的销量为0 final_result = final_result.unstack(fill_value=0).reset_index() # 调整列顺序,匹配你的期望输出 final_result = final_result[["PRODUCT_ID", "1-3", "4-7", "8-15", ">16"]] # 查看结果 print(final_result)
关键步骤解释
- 日期排序:必须按产品和日期排序,否则后续的连续判断会出错。
- 连续块识别:
diff()计算日期差,cumsum()给每个连续时间段分配唯一编号——比如0E4234的01-08、02-08会被分到同一个块,07-08到10-08是另一个块。 - 块统计:每个块计算连续天数(用
nunique确保同一天多条记录只算1天)和总销量。 - 区间映射与汇总:把每个块的天数映射到指定区间,最后按产品和区间求和,用
unstack()转成你需要的宽表格式,缺失的区间自动填充0。
验证示例
拿你给出的0E4234数据举例:
- 第一个连续块(01-08、02-08):连续2天,属于「1-3」区间,总销量2+7=9
- 第二个连续块(07-08、08-08、09-08、10-08):连续4天,属于「4-7」区间,总销量3+1+2+1=7
- 最终结果里0E4234的「1-3」为9,「4-7」为7,其余为0,完全符合你的期望。
内容的提问来源于stack exchange,提问作者san
相关产品推荐
相关产品推荐

