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

如何用Pandas按ID获取最后一次状态变更的首次日期?

解决方案

问题分析

你需要的是每个ID最后一次状态变更后,该状态的首次出现日期,而非所有历史状态的最早日期。之前的分组取最小日期会保留所有状态的历史记录,无法聚焦到最后一次变更的节点。

实现步骤与代码

import pandas as pd

# 原始数据处理(修正日期笔误:'17/01/202'改为'17/01/2020')
data = {'id': ['1','1','1','1','2','2','2','2','2','3','3','3','3','3','3','3'],
        'status': ['Active','Active','Active','Pending Action','Pending Action','Pending Action','Active','Pending Action','Active','Draft','Active','Draft','Draft','Draft','Active','Draft'],
        'calc_date_id':['05/07/2022','07/06/2022','31/08/2021','01/07/2021','20/11/2022','25/10/2022','02/04/2022','28/02/2022','01/07/2021','23/06/2022','15/06/2022','07/04/2022','09/11/2022','18/08/2020','19/03/2020','17/01/2020']
        }                 

df = pd.DataFrame(data)
# 转换日期(注意日/月/年格式,需指定dayfirst=True)
df['calc_date_id'] = pd.to_datetime(df['calc_date_id'], dayfirst=True)

# 1. 按ID分组,每组内按日期升序排序,还原时间顺序
df_sorted = df.sort_values(['id', 'calc_date_id'], ascending=[True, True]).reset_index(drop=True)

# 2. 标记同ID下状态发生变更的行(当前行与上一行状态不同)
df_sorted['status_changed'] = df_sorted.groupby('id')['status'].apply(lambda x: x != x.shift())

# 3. 筛选所有状态变更节点(包括每个ID的初始状态,用fillna(True)处理第一行的NaN)
df_changes = df_sorted[df_sorted['status_changed'].fillna(True)]

# 4. 取每个ID的最后一次状态变更节点,即为目标结果
result = df_changes.groupby('id').last().reset_index()[['id', 'status', 'calc_date_id']]

print(result)

输出结果

id           status calc_date_id
0  1           Active   2021-08-31
1  2  Pending Action   2022-10-25
2  3            Draft   2022-06-23

关键逻辑说明

  1. 排序:确保每个ID的状态按时间顺序排列,才能准确追踪变更节点。
  2. 标记变更:用shift()对比当前行与上一行的状态,找出所有状态切换的位置。
  3. 筛选节点:保留每个状态首次出现的行(包括初始状态),形成状态变更历史序列。
  4. 取最后一次变更:每个ID的最后一个变更节点,就是最后一次状态切换后的首次日期。

内容的提问来源于stack exchange,提问作者mali

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 15:31:41