Pandas如何按同月/周/日分组统计Stuffed列日期与NaT的唯一容器数
实现思路
核心问题定位
现有代码无法统计未装柜数据的核心原因有两个:
- pandas的
pd.Grouper对时间类分组键默认开启dropna=True,Stuffed为NaT的记录会被直接过滤,不参与分组聚合 - 未装柜的记录本身没有有效Stuffed日期,没有时间锚点,无法直接匹配到月/周/日的时间分桶中,需要先明确统计口径再做计算
分步实现流程
1. 前置数据清洗
容器ID存在多条重复条目,直接分组会导致计数偏差,首先做去重校准:
- 按Stuffed列降序排序,把有有效日期的记录排在前面
- 按Container ID去重,优先保留带有效Stuffed日期的记录,避免同一个ID同时被标记为已装、未装
import numpy as np # 排序:有效日期的记录前置,NaT记录后置 df_sorted = df.sort_values('Stuffed', ascending=False, na_position='last') # 按容器ID去重,保留有效的记录 df_clean = df_sorted.drop_duplicates(subset=['Container'], keep='first')
2. 分口径实现统计逻辑
根据常见的业务统计场景,两种可落地的实现方式:
口径1:动态累计统计——每个时间周期的已装数量、截至当期末的累计未装数量
这是仓储场景最常用的统计逻辑,匹配原有按Stuffed时间分桶的逻辑:
- 先计算全库去重的容器总规模
- 按原逻辑计算每个月/周/日的已装去重容器数
- 滚动计算累计已装量,对应时间节点的未装数=总容器数 - 截至该节点的累计已装量
# 计算全库去重的容器总数 total_container = df_clean['Container'].nunique() # 按时间维度统计已装柜数,freq参数可根据需求换为'M'(月)/'W'(周)/'D'(日) shipped_by_period = df_clean.groupby([pd.Grouper(key='Stuffed', freq='M')])['Container'].nunique() # 计算每个周期的累计已装量 cum_shipped = shipped_by_period.cumsum() # 拼接最终结果:当期已装数、期末剩余未装数 final_result = pd.DataFrame({ '当期已装柜数': shipped_by_period, '期末剩余未装柜数': total_container - cum_shipped })
口径2:计划批次统计——每个计划周期内的已装/未装数量
如果数据表中存在对应容器的计划装柜时间列(比如PlanStuffed),需要统计每个计划批次内的装柜完成情况:
- 先给全量数据打装柜状态标记
- 以计划时间为分桶锚点,同时按装柜状态分组,统计去重容器数
# 打状态标记 df_clean['装柜状态'] = np.where(df_clean['Stuffed'].notna(), '已装柜', '未装柜') # 按计划时间分月/周/日,按状态分组统计 stat_by_plan = df_clean.groupby([ pd.Grouper(key='PlanStuffed', freq='M'), # 替换为实际的计划时间列名 '装柜状态' ])['Container'].nunique().unstack()
注意事项
- 如果需要单独统计无明确装柜时间的未装柜容器数,可将Grouper的
dropna参数设为False,NaT的记录会单独聚为一组,无时间标签 - 切换周/日统计维度时,仅需替换
freq参数值,无需调整其他逻辑
内容的提问来源于stack exchange,提问作者SanctaMariaMaterDeiOraProNobis
相关产品推荐
相关产品推荐

