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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 00:15:57