将工作日添加到带有日期的pandas数据框架中,并跳过节假日



我有一个包含日期的数据框,如下表所示。第一块是它应该的样子,第二块是我把BDays加起来得到的。这是一个完成后应该看起来像的示例。我想使用第一列,并在日期上添加5个工作日,但如果这5个工作日与假日重叠(如21年2月15日),那么我需要额外添加一天。使用pandas.tseries.offsets import BDay添加5Bday相当简单,但在使用数据帧时不能跳过假日。

我尝试使用pandas.tseries.holiday import USFederalHolidayCalendar,工作日和工作日历模块,但无法弄清楚。有人知道我能做什么吗?

正确的例子
tbody> <<tr>
DATEEXIT DATE +5
2021/02/092021/02/17
2021/02/102021/02/18

输入数据

df = pd.DataFrame(['2021-02-09', '2021-02-10', '2021-06-28', '2021-06-29', '2021-07-02'], columns=['DATE'])
df['DATE'] = pd.to_datetime(df['DATE'])

建议使用apply

from pandas.tseries.holiday import USFederalHolidayCalendar
from pandas.tseries.offsets import BDay
def offset_date(start, offset):
return start + pd.offsets.CustomBusinessDay(n=offset, calendar=USFederalHolidayCalendar())
offset = 5
df['END'] = df.apply(lambda x: offset_date(x['DATE'], offset), axis=1)
DATE        END
2021-02-09  2021-02-17
2021-02-10  2021-02-18
2021-06-28  2021-07-06
2021-06-29  2021-07-07
2021-07-02  2021-07-12

PS:如果您想使用特定的日历,如纽约证券交易所,而不是默认的USFederalHolidayCalendar,我建议按照这个答案中的说明,创建一个自定义日历。

我不推荐的替代方案

目前,据我所知,熊猫不支持矢量化方法来解决你的问题。但是,如果你想遵循你提到的类似的方法,以下是你应该做的。

首先,您必须定义一个任意远的end日期,其中包括您可能需要的所有时期,并使用它来创建假期列表。

holidays = USFederalHolidayCalendar().holidays(start='2021-02-09', end='2030-02-09')

然后,通过holidays参数而不是calendarholidays列表传递给CustomBusinessDay,以生成所需的偏移量。

offset = 5
bday_us = pd.offsets.CustomBusinessDay(n=offset, holidays=holidays)
df['END'] = df['DATE'] + bday_us

然而,这种方法并不是一个真正的矢量化解决方案尽管看起来是这样。请参阅以下SO回答以进一步澄清。实际上,这种方法可能在进行效率不高的转换。这就是它产生以下警告的原因。

PerformanceWarning:非矢量化的DateOffset被应用到Series或DatetimeIndex

这是一种方法

import pandas as pd
from pandas.tseries.holiday import USFederalHolidayCalendar
from datetime import timedelta as td
def get_exit_date(date):
holiday_list = cals.holidays(start=date, end=date + td(weeks=2)).tolist()
# 6 periods since start date is included in set
n_bdays = pd.bdate_range(start=date, periods=6, freq='C', holidays=holiday_list)
return n_bdays[-1]
df = pd.read_clipboard()
cals = USFederalHolidayCalendar()
# I would convert this to datetime
df['DATE'] = pd.to_datetime(df['DATE'])
df['EXIT DATE +5'] = df['DATE'].apply(get_exit_date)

这是使用bdate_range返回一个日期时间索引

结果:

DATE    EXIT DATE +5
0   2021-02-09  2021-02-17
1   2021-02-10  2021-02-18

另一个选择是不动态创建假期列表。你也可以选择一个开始日期,把它放在函数外面,像这样:

def get_exit_date(date):
# 6 periods since start date is included in set
n_bdays = pd.bdate_range(start=date, periods=6, freq='C', holidays=holiday_list)
return n_bdays[-1]
df = pd.read_clipboard()
cals = USFederalHolidayCalendar()
holiday_list = cals.holidays(start='2021-01-01').tolist()
# I would convert this to datetime
df['DATE'] = pd.to_datetime(df['DATE'])
df['EXIT DATE +5'] = df['DATE'].apply(get_exit_date)

最新更新