按CODE分组计算连续8个月NORMAL_PP累积值的问题排查
解决按CODE分组计算连续8个月累积值的NaN问题
问题背景
现有df_normales DataFrame,结构为6408行3列:
CODE MONTH NORMAL_PP 0 000261 January 111.4 ... 6407 002412 December 236.7
需求是按CODE分组,计算NORMAL_PP的连续8个月累积值,要覆盖1月-8月、2月-9月……直到9月-次年4月的所有组合,最终输出格式要求包含两位月份编码的DATE_START、DATE_END。
原代码运行后出现大量NaN值,无法获取完整的连续累积结果。
原代码问题分析
原代码存在几个关键问题:
- 字段名混淆:原始数据用
MONTH列,但代码里错误使用DATE列,逻辑不匹配 - 手动添加单行的方式无法覆盖所有跨年连续月份场景
- rolling操作的方向反转导致末尾出现NaN,且未处理分组内数据的完整性
- 存在拼写错误:
assign里用了FECHA,但实际列名应为DATE - 使用
append循环拼接DataFrame,效率低且易出错
修正后的解决方案
以下是完整的修正代码,逻辑清晰且能生成符合要求的结果:
import pandas as pd # 第一步:给月份映射成数字编码,方便后续计算 month_map = { 'January': '01', 'February': '02', 'March': '03', 'April': '04', 'May': '05', 'June': '06', 'July': '07', 'August': '08', 'September': '09', 'October': '10', 'November': '11', 'December': '12' } # 转换MONTH为两位编码,同时转成数字方便计算 df_normales['MONTH_CODE'] = df_normales['MONTH'].map(month_map).astype(int) # 初始化结果DataFrame result = pd.DataFrame() # 按CODE分组处理 for code, group in df_normales.groupby('CODE'): # 按月份编码排序,确保顺序正确 group_sorted = group.sort_values('MONTH_CODE').reset_index(drop=True) # 拼接一份当前组的数据到末尾,处理跨年的连续8个月(比如9月到次年4月) # 拼接后的月份编码加12,模拟下一年的月份 group_extended = pd.concat([ group_sorted, group_sorted.assign(MONTH_CODE=lambda x: x['MONTH_CODE'] + 12) ]).reset_index(drop=True) # 计算连续8个月的累积值,min_periods=8确保只有8个完整数据才计算 group_extended['CUMULATIVE_PP'] = group_extended['NORMAL_PP'].rolling(window=8, min_periods=8).sum() # 过滤出有效的起始行:前9个月份(对应1-9月作为起始,覆盖到次年4月) valid_rows = group_extended.iloc[:9].copy() # 计算DATE_END:起始月份+7,超过12的取模12,注意处理0的情况(12月+7=19→19%12=7→07) valid_rows['DATE_END_CODE'] = valid_rows['MONTH_CODE'].apply(lambda x: (x + 7) % 12) valid_rows['DATE_END_CODE'] = valid_rows['DATE_END_CODE'].replace(0, 12).astype(str).str.zfill(2) # 转DATE_START为两位编码 valid_rows['DATE_START'] = valid_rows['MONTH_CODE'].astype(str).str.zfill(2) # 整理成目标格式 valid_rows = valid_rows[['DATE_START', 'CUMULATIVE_PP', 'DATE_END_CODE', 'CODE']] valid_rows.columns = ['DATE_START', 'NORMAL_PP', 'DATE_END', 'CODE'] # 合并到结果 result = pd.concat([result, valid_rows], ignore_index=True) # 查看结果 print(result.head())
代码说明
- 月份编码转换:把英文月份转成数字编码,方便后续的加减和排序
- 扩展分组数据:将每组数据拼接一份(月份编码+12),解决跨年连续8个月的计算问题
- 滚动累积计算:用
rolling(8, min_periods=8)确保只有凑齐8个月份才计算,避免NaN - 月份编码转换回两位格式:处理跨年的月份编码,比如12月+7个月是次年7月,转成
07 - 结果整理:过滤出有效的起始行(共9组,对应1-9月起始),调整列名到目标格式
内容的提问来源于stack exchange,提问作者Javier
相关产品推荐
相关产品推荐

