Pandas按id分组后为每组添加下一个工作日的新行
完整解决方案
步骤1:统一列名并转换日期类型
你的初始DataFrame中日期列名为'd',但后续代码和期望结果里用的是'Date',先统一列名,同时将日期列转为Pandas的datetime64类型(方便使用工作日偏移量):
import pandas as pd from pandas.tseries.offsets import BDay import datetime # 初始DataFrame df = pd.DataFrame(data={ 'd': [datetime.date(2010,12,30), datetime.date(2010,12,31), datetime.date(2010,12,30),datetime.date(2010,12,31)], 'id': [1,1,2,2], 'val': [10,200, 90,420] }) # 重命名列并转换日期类型 df = df.rename(columns={'d': 'Date'}).astype({'Date': 'datetime64[ns]'})
步骤2:编写分组添加行的函数
修正你之前的函数错误,逻辑上确保只修改最后一行的日期为下一个工作日,其余列保留(val设为NaN):
def add_next_business_day_row(group): # 复制组内最后一行数据,避免修改原数据 new_row = group.iloc[-1].copy() # 计算下一个工作日 new_row['Date'] = new_row['Date'] + BDay(1) # 将val设为缺失值 new_row['val'] = pd.NA # 追加新行到组中 return pd.concat([group, new_row.to_frame().T], ignore_index=True) # 分组应用函数并重置索引 result_df = df.groupby('id', group_keys=False).apply(add_next_business_day_row).reset_index(drop=True)
步骤3:查看结果
运行后result_df的输出与期望一致:
Date id val 0 2010-12-30 1 10.0 1 2010-12-31 1 200.0 2 2011-01-01 1 NaN 3 2010-12-30 2 90.0 4 2010-12-31 2 420.0 5 2011-01-01 2 NaN
错误原因说明
你之前报错AttributeError: 'DataFrame' object has no attribute 'Date',是因为初始DataFrame的日期列名为'd'而非'Date',代码误用了不存在的列名;同时原函数中x.Date + BDay(1)是对整列日期加偏移,而非取最后一行的日期,逻辑有误。
高效替代方案(避免apply)
如果数据量较大,groupby.apply效率偏低,可改用以下方法:
# 提取每组最后一行,计算下一个工作日 last_rows = df.groupby('id').last().reset_index() last_rows['Date'] = last_rows['Date'] + BDay(1) last_rows['val'] = pd.NA # 合并原数据和新行,按id排序 result_df = pd.concat([df, last_rows], ignore_index=True).sort_values(by=['id', 'Date']).reset_index(drop=True)
该方法效率更高,结果与之前一致。
内容的提问来源于stack exchange,提问作者Bazman
相关产品推荐
相关产品推荐

