Let's say that you have a dataframe with dates that not only range multiple holidays, but they range multiple seasons:
Date_x Date_y
0 2020-12-22 2021-01-01
1 2020-06-20 2020-07-11
3 2020-02-11 2020-03-27
4 2020-05-22 2020-06-27
In order to get 1. Season
and 2. Holiday
:
- I built off the link you shared to customize seasons
- I tried to avoid "third-party" libraries and chose to use the
USFederalHolidayCalendar
from the pandas
holiday
library; because, I thought that would be more reliable; however, I do not have much experieince with holiday libraries. Also, there are multiple calendars
that could be used from the pandas library. From there, I used the get_season(x)
and get_holiday()
function that I created. For the former, I would reference the link in your question, and the latter uses list comprehension to pull in holidays into your dataframe from the holidays
dataframe I created.
from pandas.tseries.holiday import USFederalHolidayCalendar
from datetime import datetime
import pandas as pd
cal = USFederalHolidayCalendar()
holidays = (pd.DataFrame(cal.holidays(return_name=True), columns=['Holiday'])
.reset_index()
.rename({'index': 'Date'}, axis=1))
holidays['Date'] = pd.to_datetime(holidays['Date'])
df= pd.DataFrame({'Date_x': {0: '2020-12-22', 1: '2020-06-20', 2: '2020-02-11', 3: '2020-05-22'},
'Date_y': {0: '2021-01-01', 1: '2020-07-11', 2: '2020-03-27', 3: '2020-06-27'}})
df['Date_x'] = pd.to_datetime(df['Date_x'])
df['Date_y'] = pd.to_datetime(df['Date_y'])
Y = 2000 # dummy leap year to allow input X-02-29 (leap day)
seasons = [('Winter', (date(Y, 1, 1), date(Y, 3, 20))),
('Spring', (date(Y, 3, 21), date(Y, 6, 20))),
('Summer', (date(Y, 6, 21), date(Y, 9, 22))),
('Fall', (date(Y, 9, 23), date(Y, 12, 20))),
('Winter', (date(Y, 12, 21), date(Y, 12, 31)))]
def get_season(x):
x = x.replace(year=Y)
return next(season for season, (start, end) in seasons
if start <= x <= end)
def get_holiday():
return pd.DataFrame([(h,y,z) for (h,d) in zip(holidays['Holiday'], holidays['Date'])
for (y, z) in zip(df['Date_x'], df['Date_y']) if y.date() <= d.date() if d.date() <= z.date()], columns=['Holiday', 'Date_x', 'Date_y'])
s1 = df['Date_x'].apply(lambda x: get_season(x))
s2 = df['Date_y'].apply(lambda x: get_season(x))
df['Season']= [', '.join(list(set([x,y]))) for (x,y) in zip(s1,s2)]
dft = get_holiday()
dft = dft.groupby(['Date_x', 'Date_y'])['Holiday'].apply(lambda x: ', '.join(list(x)))
df = pd.merge(df, dft, how='left', on=['Date_x', 'Date_y'])
df
Out[32]:
Date_x Date_y Season Holiday
0 2020-12-22 2021-01-01 Winter Christmas, New Years Day
1 2020-06-20 2020-07-11 Summer, Spring July 4th
2 2020-02-11 2020-03-27 Spring, Winter Presidents Day
3 2020-05-22 2020-06-27 Summer, Spring Memorial Day