如何在Python Pandas DataFrame中识别最新连续相同值序列
问题描述
我有一个包含Id和Date(格式为dd-mm-yyyy)的Pandas DataFrame,创建代码如下:
import pandas as pd data={'Id':['A', 'B', 'C', 'A', 'B', 'C', 'B', 'C', 'A', 'C', 'B', 'C', 'B', 'C', 'A', 'B', 'C', 'A', 'B', 'C'], 'Date':['20-10-2022', '20-10-2022', '20-10-2022', '21-10-2022', '21-10-2022', '21-10-2022', '22-10-2022', '22-10-2022', '23-10-2022', '23-10-2022', '24-10-2022', '24-10-2022', '25-10-2022', '25-10-2022', '26-10-2022', '26-10-2022', '26-10-2022', '27-10-2022', '27-10-2022', '27-10-2022']} df=pd.DataFrame.from_dict(data)
对应的DataFrame内容:
Id Date 0 A 20-10-2022 1 B 20-10-2022 2 C 20-10-2022 3 A 21-10-2022 4 B 21-10-2022 5 C 21-10-2022 6 B 22-10-2022 7 C 22-10-2022 8 A 23-10-2022 9 C 23-10-2022 10 B 24-10-2022 11 C 24-10-2022 12 B 25-10-2022 13 C 25-10-2022 14 A 26-10-2022 15 B 26-10-2022 16 C 26-10-2022 17 A 27-10-2022 18 B 27-10-2022 19 C 27-10-2022
我需要得到每个Id的最新连续出现序列对应的起止日期,但尝试的代码只能得到每个Id的首次和末次出现日期:
# 查找每个Id的首次和末次出现 df_first_duplicate = df.drop_duplicates(subset=['Id'], keep='first') df_first_duplicate.rename(columns = {'Date':'DateOfFirstOccurance'}, inplace = True) df_first_duplicate.reset_index(inplace = True, drop = True) df_last_duplicate = df.drop_duplicates(subset=['Id'], keep='last') df_last_duplicate.rename(columns = {'Date':'DateOfLastOccurance'}, inplace = True) df_last_duplicate.reset_index(inplace = True, drop = True) # 合并两个结果 df_merged = pd.merge(df_first_duplicate, df_last_duplicate, on='Id')
得到的输出:
Id DateOfFirstOccurance DateOfLastOccurance 0 A 20-10-2022 27-10-2022 1 B 20-10-2022 27-10-2022 2 C 20-10-2022 27-10-2022
请问该如何修改代码以得到目标结果?
解决方案
核心思路是先识别每个Id的连续出现分组,再筛选出每个Id的最新分组,最后提取该分组的起止日期。具体步骤如下:
步骤1:转换日期格式
先将字符串类型的Date转为Pandas日期类型,确保能正确判断日期连续性:
df['Date'] = pd.to_datetime(df['Date'], format='%d-%m-%Y')
步骤2:标记连续序列分组
对每个Id,判断当前日期与前一个日期是否连续(间隔1天),通过累积求和生成连续序列的分组标签:
# 按Id分组,计算相邻日期的间隔是否为1天 df['is_continuous'] = df.groupby('Id')['Date'].diff().dt.days == 1 # 填充每个Id的第一条数据为True(无前置日期,默认属于第一个连续组) df['is_continuous'] = df['is_continuous'].fillna(True) # 生成分组ID:每次出现不连续时,分组号递增 df['group_id'] = df.groupby('Id')['is_continuous'].cumsum()
步骤3:提取最新连续组的起止日期
先计算每个分组的起止日期,再筛选出每个Id的最新分组(最大的group_id):
# 计算每个(Id, group_id)分组的起止日期 grouped = df.groupby(['Id', 'group_id']).agg( start_date=('Date', 'min'), end_date=('Date', 'max') ).reset_index() # 获取每个Id的最新分组ID latest_groups = grouped.groupby('Id')['group_id'].max().reset_index() # 合并得到最新分组的起止日期 result = pd.merge(latest_groups, grouped, on=['Id', 'group_id']).drop('group_id', axis=1) # 将日期转回原字符串格式 result['start_date'] = result['start_date'].dt.strftime('%d-%m-%Y') result['end_date'] = result['end_date'].dt.strftime('%d-%m-%Y')
最终结果
运行上述代码后,得到的目标DataFrame如下:
Id start_date end_date 0 A 26-10-2022 27-10-2022 1 B 24-10-2022 27-10-2022 2 C 20-10-2022 27-10-2022
内容的提问来源于stack exchange,提问作者Pavan
相关产品推荐
相关产品推荐

