ドメイン知識

祝日フラグの作成と連休の反映

時系列分析を行う際には、曜日配列や祝日の配置が重要です。
祝日が月曜日や金曜日であれば土日と合わせて3連休になりますし、年末年始やお盆はカレンダー上は平日であっても、実際には大型連休と呼ばれ帰省ラッシュとなります。
このページでは、3連休や大型連休などを反映した祝日マートの作成方法についてまとめます。

祝日マートの作成

はじめに、Pythonで祝日と曜日情報を追加したマートを作成します。
jpholidayというパッケージを利用することで、日本の祝日情報を取得できます。
Prophetのmake_holidays_df関数でも祝日フラグを作成できますが、振替休日が反映されていないなど問題が多いので、jpholidayの使用をおすすめします(25/3/1現在)。

Python
import pandas as pd
import jpholiday

# 関数定義:祝日マートの作成
def get_holidays(start, end):
  '''
  start, str, YYmmdd
  end, sr, YYmmdd
  '''
  df = pd.DataFrame(pd.date_range(start, end), columns=['date'])
  # 年を除き、月日のみを抜粋
  df['mmdd'] = df['date'].dt.strftime('%m-%d')
  # 祝日フラグ
  df['holiday_flg'] = df['date'].map(jpholiday.is_holiday).astype(int)
  # 祝日名称
  df['holiday_name'] = df['date'].map(jpholiday.is_holiday_name)
  # 曜日
  df['dayname'] = df['date'].dt.day_name()

  return df

# 確認用に下記期間で祝日マート作成
# 2024年:8月の山の日とお盆が一体化
# 2026年:9月に国民の祝日がある
start = '20240101'
end = '20261231'
# 祝日マート作成
df_flg = get_holidays(start=start, end=end)
display(df_flg.head(2))
display(df_flg.tail(2))
# 確認用に祝日一覧取得
display(df_flg[df_flg['holiday_flg']==1].head(3))

# date	mmdd	holiday_flg	holiday_name	dayname
# 0	2024-01-01	01-01	1	元日	Monday
# 1	2024-01-02	01-02	0	None	Tuesday

# date	mmdd	holiday_flg	holiday_name	dayname
# 1094	2026-12-30	12-30	0	None	Wednesday
# 1095	2026-12-31	12-31	0	None	Thursday

# date	mmdd	holiday_flg	holiday_name	dayname
# 0	2024-01-01	01-01	1	元日	Monday
# 7	2024-01-08	01-08	1	成人の日	Monday
# 41	2024-02-11	02-11	1	建国記念の日	Sunday

連休・大型連休の反映

次に、3連休や大型連休を祝日マートに反映します。
ここまでで作成した祝日マートは、あくまでカレンダー上の祝日を反映したものであるため、年末年始の12/31や1/3は祝日扱いでありませんし、火~木曜日の祝日と3連休となる月曜日の祝日を区別していません。
元のマートではholiday_nameに祝日の名称を記載していますが、実際に役立つ情報は、年末年始や3連休、単独の祝日(火~木曜日の祝日)といった情報です。
このため、holiday_nameを修正し、3連休や大型連休の場合は実態に合わせて土日も同名の祝日扱いとします。

以下のコードでは、次のような処理を行っています。
①土日が祝日の場合はその日を祝日とは見なさない(例:土曜の祝日は普通の週末)
②金曜または月曜日が祝日の場合は、土日も含めて「連休」という祝日
③火~木曜日が祝日の場合は、「単独祝日」という祝日に集約
④年末年始・GW・お盆期間は、日付を指定して期間内の全ての日を祝日扱い
⑤8/11の山の日がお盆期間と連続する場合は、山の日や土日も含めてお盆休み扱い
⑥5/6が月~水曜日の場合は振替休日となるので、GW扱い
⑦連休/大型連休が土日と連続する場合は大型連休に含める
⑧9月の祝日が近接して国民の祝日が発生する場合(例:2026年)は、連休として扱う

Python
# ###########################################
# 関数定義:前後2日分の祝日フラグ・名称を追加/更新
# ###########################################
def add_before_after_holidays(df):
  '''
  df: DataFrame, 祝日フラグ・名称を追加するdf
  '''
  # holiday_nameが欠損ではない日のholiday_flgは全て1にする
  df.loc[~df['holiday_name'].isna(), 'holiday_flg'] = 1

  # 前後2日分の祝日フラグ・名称を追加/更新
  df['holiday_flg_before'] = df['holiday_flg'].shift(1)
  df['holiday_name_before'] = df['holiday_name'].shift(1)
  df['holiday_flg_before2'] = df['holiday_flg'].shift(2)
  df['holiday_name_before2'] = df['holiday_name'].shift(2)

  df['holiday_flg_after'] = df['holiday_flg'].shift(-1)
  df['holiday_name_after'] = df['holiday_name'].shift(-1)
  df['holiday_flg_after2'] = df['holiday_flg'].shift(-2)
  df['holiday_name_after2'] = df['holiday_name'].shift(-2)

  # 金曜日や月曜日に祝日や大型連休が来る場合は、土日も連休扱いにする
  # 土曜日の連休判定
  # 金曜が祝日なら土日(祝日名なし)も連休
  df.loc[(df['dayname']=='Saturday')&(df['holiday_name'].isna())&(df['holiday_flg_before']==1), 'holiday_name'] = df['holiday_name_before']
  df.loc[(df['dayname']=='Sunday')&(df['holiday_name'].isna())&(df['holiday_flg_before2']==1), 'holiday_name'] = df['holiday_name_before2']
  # 月曜が祝日なら土日(祝日名なし)も連休
  df.loc[(df['dayname']=='Sunday')&(df['holiday_name'].isna())&(df['holiday_flg_after']==1), 'holiday_name'] = df['holiday_name_after']
  df.loc[(df['dayname']=='Saturday')&(df['holiday_name'].isna())&(df['holiday_flg_after2']==1), 'holiday_name'] = df['holiday_name_after2']

  return df

# ###########################################
# 関数定義:連休や大型連休を祝日マートに追加
# ###########################################
def add_holidays(df):
  '''
  df: DataFrame, 祝日マート
  '''
  # Prophet投入用に祝日名称は予測用に集約しておく
  # 土日の祝日名称は消しておく(単独では普通の週末と変わらない、連休の場合は後で上書きできるように)
  daynames_weekend = ['Saturday', 'Sunday']
  df.loc[df['dayname'].isin(daynames_weekend), 'holiday_name'] = None
  df.loc[df['dayname'].isin(daynames_weekend), 'holiday_flg'] = 0

  # 月曜や金曜に祝日がある場合は連休
  daynames_shumatsu = ['Monday', 'Friday']
  df.loc[(df['dayname'].isin(daynames_shumatsu))&(df['holiday_flg']==1), 'holiday_name'] = '連休'

  # 火~木曜日の祝日は単独祝日(大型連休該当の場合は後で上書き)
  daynames_nakabi = ['Tuesday', 'Wednesday', 'Thursday']
  df.loc[(df['dayname'].isin(daynames_nakabi))&(df['holiday_flg']==1), 'holiday_name'] = '単独祝日'

  # 大型連休の追加
  # 年末年始(12/29-1/3)
  df.loc[(df['mmdd']>='12-29')|(df['mmdd']<='01-03'), 'holiday_name'] = '年末年始'
  # GW(4/29-5/5)
  df.loc[(df['mmdd']>='04-29')&(df['mmdd']<='05-05'), 'holiday_name'] = 'GW'
  # お盆(8/13-16)
  df.loc[(df['mmdd']>='08-13')&(df['mmdd']<='08-16'), 'holiday_name'] = 'お盆休み'

  # 8/11の山の日が金~日曜の場合は、お盆とつながるのでお盆扱いにする
  df.loc[(df['mmdd']=='08-10')&(df['dayname'].isin(['Saturday'])), 'holiday_name'] = 'お盆休み'
  df.loc[(df['mmdd']=='08-11')&(df['dayname'].isin( ['Friday', 'Saturday', 'Sunday'])), 'holiday_name'] = 'お盆休み'
  df.loc[(df['mmdd']=='08-12')&(df['dayname'].isin( ['Saturday', 'Sunday', 'Monday'])), 'holiday_name'] = 'お盆休み'

  # 5/6が月曜日の場合は振替休日となるのでGW扱い
  daynames_furikae = ['Monday', 'Tuesday', 'Wednesday']
  df.loc[(df['mmdd']=='05-06')&(df['dayname'].isin(daynames_furikae)), 'holiday_name'] = 'GW'

  # 連休/大型連休が土日と連続する場合は大型連休に含める
  # 前後2日分の祝日フラグ/名称を更新
  df = add_before_after_holidays(df=df)

  # シルバーウィークのように例外的に国民の祝日ができる場合は個別対応
  # 単独祝日の前日が祝日の場合は連休扱い
  df.loc[(df['holiday_name']=='単独祝日')&(~df['holiday_name_before'].isna()), 'holiday_name'] = '連休'
  df.loc[(df['holiday_name']=='単独祝日')&(~df['holiday_name_before'].isna())&(~df['holiday_name_before2'].isna()), 'holiday_name'] = '連休'

  # holiday_nameが欠損ではない日のholiday_flgは全て1にする
  df.loc[~df['holiday_name'].isna(), 'holiday_flg'] = 1

  return df

# ###########################################
# 関数実行・出力
# ###########################################
# 連休や大型連休を祝日マートに追加
df_name = add_holidays(df=df_flg)
# 不要カラム削除
print(df_name.columns)
rm_cols = [
    'holiday_flg_before', 'holiday_name_before', 'holiday_flg_before2', 'holiday_name_before2', 'holiday_flg_after', 'holiday_name_after', 'holiday_flg_after2', 'holiday_name_after2'
]
df_out = df_name.drop(columns=rm_cols)

以上のような処理を行うことで、祝日情報から実態に合わせた休日カレンダーを作ることができます。

参考文献

pandas.DataFrameに祝日の特徴量を作る u++の備忘録 2025/3/2閲覧
国民の祝日 ウィキペディア 2025/3/1閲覧
カレンダー 便利.com 2025/3/1閲覧

-ドメイン知識
-, , ,