Pythonでの時系列データの扱い4 〜 「祝日の取得」および「祝日を考慮した営業日の取得」

前回「Pythonでの時系列データの扱い3 〜 時系列データの頻度設定」の続き。

前回、次のようなコードで月の最終営業日を取得したが、祝日が考慮されていないことが判明した(当然だが・・・)。

#coding:utf-8
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import datetime
import dateutil

## 月の最終営業日(BusinessMonthEnd)毎に作成
index = pd.date_range(start='2016/1/1', end='2016/11/30', freq='BM')
print index

そこで今回は、月の最終営業日を取得すべく、下記を学習していく。

1.日本の祝日を取得する方法
2.日本の営業日を取得する方法
3.指定データの各月の最終営業日を取得する方法

1.日本の祝日を取得する方法
結論から言うと、自作した方がいいと思うw。

1.カレンダー用のテーブルを自作して、祝日判定用のカラムを用意して、年末に翌年分のデータを登録しておけばいいと思う。
祝日については内閣府が公表している。
2.カレンダー用のテーブルを作成したら、そこにアクセスして、基準日が祝日か否かを判定するAPIを作成すればいいと思う。
※)判定の都度、DBへのIOが発生するのを嫌うなら、処理前にメモリにロードしておくなり、何らかの方法はある。

こうしておけば、例えば、祝日以外の特別な日(学校の設立記念日による祝日、結婚記念日、etc)を判定したい場合にも応用が効くだろう。

いやいや、そんな面倒なことをしたくないからライブラリが豊富なpythonを使っているのだという場合(まさに自分がそう)には、どうしようと思ってpipで調べたら「japanese_holiday 0.0.4」が良さそう。
※)「japan_holiday 0.0.8」というのもあった。こちらは日本人が作成したようなので、こちらのほうが良いかも。
ただ、いずれもGoogleカレンダーから取得するため、Google API tokenが必要なところが面倒

結局、APIトークン取得する手間と祝日登録する手間の比較のようになったので、ここで中断。
続きは後日書く。
テーマが今回のテーマとは少しずれるので、別のエントリーとして「pythonのライブラリ「japanese_holiday 0.0.4」を使用して日本の祝日を取得する」に書いた。そちらを参照。
Google Calendar API」を使用する前提。

2.日本の営業日を取得する方法
pythonのライブラリ「japanese_holiday 0.0.4」を使用して日本の祝日を取得する」を参考に祝日を取得できた前提で、話を進める。

営業日を取得するために、今回は次の手順を踏む。

1.workdaysライブラリをインストールする
2.date型の休日リストを作成する
3.workdaysの関数を利用する

例えば、「2016-11-18」から営業日を取得する例が次。

#coding:utf-8
import japanese_holiday
import datetime
import dateutil
import workdays

######## 祝日取得の期間設定 ########
today = datetime.date(2016,11,18)
date_from = datetime.date(today.year-1, 1, 1)
date_to = datetime.date(today.year, 12, 31)

######## 祝日情報の取得 ########
holidays = japanese_holiday.getholidays(
"Google Calendar APIのAPIキー",
japanese_holiday.HOLIDAY_TYPE_OFFICIAL_JA,
date_from.strftime('%Y-%m-%d'),
date_to.strftime('%Y-%m-%d')
)

######## workdaysで使用できるように、文字列型の休日リストからdate型の休日リストに変換する ########
holidaysList = []
for holiday in holidays:
    holidaysList.append(datetime.datetime.strptime(holiday['start']['date'], '%Y-%m-%d').date())

# 基準日当日
print "### 基準日当日 ###"
print workdays.workday(today)
print workdays.workday(today, 0)
print workdays.workday(today, 0, holidaysList)

# 基準日からN営業日だけずらした日付を求める
print "### 基準日からN営業日だけずらした日付を求める ###"
print workdays.workday(today, 0)
print workdays.workday(today, 1)
print workdays.workday(today, 2)
print workdays.workday(today, 3)
print workdays.workday(today, 4)
print workdays.workday(today, 5)
print workdays.workday(today, 6)
print workdays.workday(today, 7)

# 休日を考慮して基準日からN営業日ずらした日付を求める
print "### 休日を考慮して基準日からN営業日ずらした日付を求める ###"
print workdays.workday(today, 0, holidaysList)
print workdays.workday(today, 1, holidaysList)
print workdays.workday(today, 2, holidaysList)
print workdays.workday(today, 3, holidaysList)
print workdays.workday(today, 4, holidaysList)
print workdays.workday(today, 5, holidaysList)
print workdays.workday(today, 6, holidaysList)
print workdays.workday(today, 7, holidaysList)

実行結果は次。
このテスト期間では、2016年11月23日が祝日「勤労感謝の日」なので、祝日を考慮した場合は除かれている。
workdays.workdayを使うと土日は除かれる。

### 基準日当日 ###
2016-11-18
2016-11-18
2016-11-18
### 基準日からN営業日だけずらした日付を求める ###
2016-11-18
2016-11-21
2016-11-22
2016-11-23
2016-11-24
2016-11-25
2016-11-28
2016-11-29
### 休日を考慮して基準日からN営業日ずらした日付を求める ###
2016-11-18
2016-11-21
2016-11-22
2016-11-24
2016-11-25
2016-11-28
2016-11-29
2016-11-30

似たようなこと以上のことが「日付処理(○営業日後の日付、月末・月初日、第○金曜日の取得)」に書かれていたので、あとはそちらを参照するか自作。

3.指定データの各月の最終営業日を取得する方法
「日付処理(○営業日後の日付、月末・月初日、第○金曜日の取得)」を参照。