如何在DataFrame中添加按ID分组的上月mark最大值列?
问题:按ID分组获取上月mark最大值并新增列
给定如下DataFrame:
import pandas as pd df = pd.DataFrame({'date':['202301','202301','202301','202301','202302','202302','202302','202302','202303','202303','202303','202304','202304'], 'mark': [1,1,2,3,1,1,1,1,1,3,1,1,1], 'id':[20,20,21,21,20,20,21,21,20,20,21,20,21]})
需要新增一列mark_previous,规则为:按id分组后,存储该ID上月mark的最大值;若为该ID的第一个月份,则填0。期望输出如下:
date mark id mark_previous 202301 1 20 0 202301 1 20 0 202301 2 21 0 202301 3 21 0 202302 1 20 1 202302 1 20 1 202302 1 21 3 202302 1 21 3 202303 1 20 1 202303 3 20 1 202303 1 21 1 202304 1 20 3 202304 1 21 1
解决方案
可以通过分组聚合+移位+合并的方式实现,具体代码如下:
# 1. 将date转换为月份周期类型,便于精准处理月份关系 df['date'] = pd.to_datetime(df['date'], format='%Y%m').dt.to_period('M') # 2. 按id和date分组,计算每个ID每月的mark最大值 monthly_max = df.groupby(['id', 'date'])['mark'].max().reset_index(name='max_mark') # 3. 按id分组,将max_mark向下移位1位(即取上月最大值),空值填充为0 monthly_max['mark_previous'] = monthly_max.groupby('id')['max_mark'].shift(1).fillna(0) # 4. 将计算结果合并回原DataFrame,匹配对应id和date的mark_previous result = df.merge(monthly_max[['id', 'date', 'mark_previous']], on=['id', 'date'], how='left') # 可选:将date转回原字符串格式(如不需要可省略) result['date'] = result['date'].dt.strftime('%Y%m') # 查看结果 print(result)
步骤说明
- 日期转换:把字符串格式的日期转为
period('M')类型,能直接识别为月份,避免日期细节干扰,后续转回原格式也很简便。 - 月度最大值聚合:同一个ID同一月份的所有行,对应的上月最大值是相同的,先聚合计算每月最大值,再匹配回原表,比直接逐行处理效率更高。
- 移位取上月值:按ID分组后使用
shift(1),可以将每个月份的最大值对应到下一个月份,第一个月份移位后得到空值,用fillna(0)替换成需求的默认值。 - 合并回原表:通过
merge将计算好的mark_previous匹配到原表的每一行,保证所有数据都能正确对应。
内容的提问来源于stack exchange,提问作者dsilva
相关产品推荐
相关产品推荐

