按id分组计算symbol字段值变更时的日期差
解决方案:按ID分组计算Symbol变更的日期差
问题分析
你的原始代码未按id分组,导致会跨ID比较symbol;同时仅对比当前行与前一行的symbol,无法实现示例中“从同一ID下前一个symbol组的起始日期计算天数差”的需求。以下是修正后的实现方案:
完整代码实现
import pandas as pd # 示例数据(可替换为你的实际数据) data = { 'id': [1,1,1,2,2,2,2,3,3], 'date': ['2022-08-26','2022-08-27','2022-08-28','2022-08-26','2022-08-27','2022-08-28','2022-08-29','2022-08-29','2022-08-30'], 'symbol': ['a','a','a','a','a','a','b','c','b'] } df = pd.DataFrame(data) # 转换日期格式为datetime df['date'] = pd.to_datetime(df['date']) # 按id分组处理 def compute_datediff(group): # 给同一id内连续相同的symbol分配组号 group['symbol_group'] = (group['symbol'] != group['symbol'].shift()).cumsum() # 获取每个symbol组的起始日期 group_start_dates = group.groupby('symbol_group')['date'].first().reset_index() # 合并起始日期到原分组 group = group.merge(group_start_dates, on='symbol_group', suffixes=('', '_start')) # 获取前一个symbol组的起始日期 group['prev_group_start'] = group['date_start'].shift() # 计算datediff:新symbol组则计算天数差,否则为0 group['datediff'] = group.apply( lambda row: (row['date'] - row['prev_group_start']).days if row['symbol_group'] > 1 else 0, axis=1 ) # 清理临时列 return group.drop(['symbol_group', 'date_start', 'prev_group_start'], axis=1) # 应用分组函数并重置索引 df = df.groupby('id').apply(compute_datediff).reset_index(drop=True) print(df)
代码说明
- 按ID分组:确保每个ID内的计算独立,不会跨ID干扰。
- 标记连续Symbol组:用
(group['symbol'] != group['symbol'].shift()).cumsum()给同一ID内连续相同的symbol生成唯一组号,区分不同的symbol阶段。 - 提取组起始日期:获取每个symbol组的第一个日期,用于计算变更时的天数差。
- 计算日期差:当进入新的symbol组时,用当前日期减去前一个组的起始日期得到天数差,其余行设为0。
输出结果
id date symbol datediff 0 1 2022-08-26 a 0 1 1 2022-08-27 a 0 2 1 2022-08-28 a 0 3 2 2022-08-26 a 0 4 2 2022-08-27 a 0 5 2 2022-08-28 a 0 6 2 2022-08-29 b 3 7 3 2022-08-29 c 0 8 3 2022-08-30 b 1
性能优化版(适合大数据集)
如果你的数据量较大,可避免使用apply提升效率:
import pandas as pd df['date'] = pd.to_datetime(df['date']) # 按id标记连续symbol组 df['symbol_group'] = df.groupby('id')['symbol'].apply(lambda x: (x != x.shift()).cumsum()) # 获取每个(id, symbol_group)的起始日期 group_start = df.groupby(['id', 'symbol_group'])['date'].first().rename('prev_start') df = df.join(group_start, on=['id', 'symbol_group']) # 按id偏移获取前一个组的起始日期 df['prev_start'] = df.groupby('id')['prev_start'].shift() # 计算datediff df['datediff'] = df['date'].sub(df['prev_start']).dt.days.fillna(0).astype(int) # 清理临时列 df = df.drop('symbol_group', axis=1) print(df)
内容的提问来源于stack exchange,提问作者Jel
相关产品推荐
相关产品推荐

