Pandas Data Offsetsで日付データを操作: BusinessMonthBeginを徹底解説


pandas.tseries.offsets.BusinessMonthBegin は、Pandas DataFrames で日付データを操作するために使用されるオフセットクラスの一つです。このオフセットは、月初めの最初の営業日 に移動します。つまり、祝日や週末を除いた最初の平日 を指します。

使い方

BusinessMonthBegin オフセットは、以下の方法で使用できます。

  • DataFrame の列にオフセットを設定
import pandas as pd

# データフレームの作成
df = pd.DataFrame({'date': pd.date_range('2023-01-01', periods=12)})

# BusinessMonthBegin オフセットを設定
df['next_month_begin'] = df['date'] + pd.tseries.offsets.BusinessMonthBegin(1)

print(df)

このコードを実行すると、以下の出力が得られます。

        date        next_month_begin
0    2023-01-01    2023-02-01
1    2023-02-01    2023-03-01
2    2023-03-01    2023-04-03
3    2023-04-01    2023-05-01
4    2023-05-01    2023-06-01
5    2023-06-01    2023-07-03
6    2023-07-01    2023-08-01
7    2023-08-01    2023-09-04
8    2023-09-01    2023-10-02
9    2023-10-02    2023-11-01
10   2023-11-01    2023-12-04
11   2023-12-04    2024-01-02
  • 日付操作
import pandas as pd

# 基準日
base_date = pd.Timestamp('2023-01-01')

# BusinessMonthBegin オフセットを使用して 1 か月後の日付を取得
next_month_begin = base_date + pd.tseries.offsets.BusinessMonthBegin(1)

print(next_month_begin)
2023-02-01 00:00:00
  • 祝日は考慮されますが、土曜日 が祝日の場合は、次の月曜日 がオフセットとして返されます。
  • BusinessMonthBegin オフセットは、米国市場の営業日 を基準としています。他の地域の営業日を使用する場合は、start_dayweekdays などのオプションを設定する必要があります。
  • BusinessMonthBegin オフセットは、BMonthBegin というエイリアスも持っています。
  • Data Offsets は、時間経過とともに変化するデータ (株価、為替レートなど) を分析する際に役立ちます。
  • Pandas には、BusinessDayOffsetBusinessHourOffset など、他にもさまざまな Data Offsets クラスがあります。


特定の祝日を考慮した BusinessMonthBegin オフセットの使用

import pandas as pd
from pandas.tseries.offsets import BusinessMonthBegin

# 基準日
base_date = pd.Timestamp('2022-12-31')

# 2023年の元旦を祝日として定義
holidays = pd.to_datetime(['2023-01-01'])

# BusinessMonthBegin オフセット (2023年の元旦を考慮)
offset = BusinessMonthBegin(1, holidays=holidays)

# 次の月初めの日付
next_month_begin = base_date + offset

print(next_month_begin)
2023-02-01 00:00:00

週末を含む BusinessMonthBegin オフセットの使用

BusinessMonthBegin オフセットはデフォルトで週末を除外しますが、weekends オプションを使用して週末を含めることができます。 以下のコードは、2023年1月1日から1ヶ月後のすべての週末を含む日付のリストを作成する例です。

import pandas as pd
from pandas.tseries.offsets import BusinessMonthBegin

# 基準日
base_date = pd.Timestamp('2023-01-01')

# 週末を含む BusinessMonthBegin オフセット
offset = BusinessMonthBegin(1, weekends=True)

# 次の月までのすべての週末の日付
dates = []
while base_date < base_date + offset(base_date):
    dates.append(base_date)
    base_date += offset

print(dates)
[Timestamp('2023-01-01 00:00:00'), Timestamp('2023-01-06 00:00:00'), Timestamp('2023-01-13 00:00:00'), Timestamp('2023-01-20 00:00:00'), Timestamp('2023-01-27 00:00:00'), Timestamp('2023-02-03 00:00:00'), Timestamp('2023-02-10 00:00:00'), Timestamp('2023-02-17 00:00:00'), Timestamp('2023-02-24 00:00:00')]

BusinessMonthBegin オフセットは米国の営業日基準ですが、start_day オプションを使用して異なる地域の営業日基準を設定することができます。 以下のコードは、日本市場の営業日基準で1ヶ月後のオフセットを返す例です。

import pandas as pd
from pandas.tseries.offsets import BusinessMonthBegin

# 基準日
base_date = pd.Timestamp('2023-01-01')

# 日本市場の営業日基準 (月曜から金曜)
offset = BusinessMonthBegin(1, start_day='mon', weekmask='Mon-Fri')

# 次の月初めの日付 (日本市場の営業日基準)
next_month_begin = base_date + offset

print(next_month_begin)
2023-02-06 00:00:00
  • 上記のコードはほんの一例です。ご自身のニーズに合わせてカスタマイズすることができます。


手動でオフセットを計算する

最も基本的な方法は、手動でオフセットを計算することです。 以下のコードは、datetime モジュールと calendar モジュールを使用して、2023年1月1日から1ヶ月後の最初の営業日を計算する例です。

import datetime
import calendar

def next_business_day(date):
    date += datetime.timedelta(days = 1)
    while date.weekday() in (calendar.SATURDAY, calendar.SUNDAY):
        date += datetime.timedelta(days = 1)
    return date

base_date = datetime.datetime(2023, 1, 1)
next_month_begin = next_business_day(base_date + relativedelta.relativedelta(months=+1))

print(next_month_begin)

この方法の長所は、柔軟性に優れていることです。 独自のルールに基づいてオフセットを計算することができます。 一方、短所は、コードが煩雑になり、エラーが発生しやすいことです。

カスタムオフセットクラスを作成する

より柔軟な代替方法として、カスタムオフセットクラスを作成することができます。 以下のコードは、BMonthBegin という名前のカスタムオフセットクラスを作成する例です。 このオフセットクラスは、BusinessMonthBegin と同様に動作しますが、start_dayweekmask などのオプションを追加することができます。

from pandas import offsets
import pandas as pd

class BMonthBegin(offsets.Offset):

    def __init__(self, start_day=1, weekmask='Mon-Fri'):
        self.start_day = start_day
        self.weekmask = weekmask

    def __repr__(self):
        return f'BMonthBegin(start_day={self.start_day}, weekmask={self.weekmask})'

    def rollforward(self, basedate):
        if basedate.weekday() == self.start_day:
            return basedate + relativedelta.relativedelta(months=+1)
        else:
            offset_days = (self.start_day - basedate.weekday()) % 7
            return basedate + relativedelta.relativedelta(days=+offset_days, months=+1)

base_date = pd.Timestamp('2023-01-01')
offset = BMonthBegin(start_day=1, weekmask='Mon-Fri')
next_month_begin = base_date + offset

print(next_month_begin)

この方法の長所は、BusinessMonthBegin よりも柔軟性に優れていることです。 独自のルールに基づいてオフセットを定義することができます。 一方、短所は、コード作成に時間がかかり、複雑になることです。

サードパーティライブラリを使用する

BusinessMonthBegin の代替となるサードパーティライブラリがいくつかあります。 例えば、dateutil ライブラリには、relativedelta モジュールが提供されており、月初めの最初の営業日を計算するための機能が含まれています。 以下のコードは、dateutil ライブラリを使用して2023年1月1日から1ヶ月後の最初の営業日を計算する例です。

from dateutil.relativedelta import relativedelta
import pandas as pd

base_date = pd.Timestamp('2023-01-01')
offset = relativedelta(months=+1, weekday=relativedelta.MO(1))
next_month_begin = base_date + offset

print(next_month_begin)

この方法の長所は、簡単に使用できることです。 サードパーティライブラリがすでに必要な機能を提供している場合、この方法が最適です。 一方、短所は、すべての環境で利用可能とは限らないことです。

pandas.tseries.offsets.BusinessMonthBegin の代替方法はいくつかありますが、それぞれ長所と短所があります。 ご自身のニーズに合った方法を選択してください。

  • 上記のコードはほんの一例です。ご自身のニーズに合わせてカスタマイズすることができます。