pandas

【Pandas】日付インデックスの頻度を判定する

MAX

Pandasで時系列データを扱う場合、大抵の場合、インデックスにはDatetimeIndexを使うことになる。

色々な頻度のデータを扱う場合、今扱っているデータの頻度が日次なのか、週次なのかなどの頻度を知りたくなることもある。

DatetimeIndexの生成時にfreqを指定していれば、freqでそのまま頻度を取得できるが、freqが設定されていない場合、Noneが返ってくる。(なおDatetimeIndexは不変なので、生成後に頻度を設定することはできず、インスタンスを再生成することになる)

Noneが返ってきた場合は、日付の間隔などから頻度を推測しても良いが、inferred_freqを使うと頻度を推測して返してくれる。

スポンサーリンク

inferred_freqで頻度の推測が可能な例

基本的にはPandasの日付Offsetで設定されている頻度に合致した場合に、inferred_freqでの推測が可能となる。

ただし、一部の日付Offsetは推測の対象外となっているものもある。

pandas日付offset-aliases

D:日次(Calendar Day)

1# 日付間隔が1日毎
2date_1d = ["2020-1-1", "2020-1-2", "2020-1-3", "2020-1-4", "2020-1-5"]
3df_1d = pd.DataFrame(data, index=date_1d)
4df_1d.index = pd.to_datetime(df_1d.index)
5print(df_1d.index.inferred_freq)
6# "D"
7
8# 日付間隔が2日毎
9date_2d = ["2020-1-1", "2020-1-3", "2020-1-5", "2020-1-7", "2020-1-9"]
10df_2d = pd.DataFrame(data, index=date_2d)
11df_2d.index = pd.to_datetime(df_2d.index)
12print(df_2d.index.inferred_freq)
13# "2D"

3日毎だと3D。10日毎だと10D。

7の倍数毎だと、後述するWとなる。

B:平日(Business day)

1# 日付間隔が1日毎、平日
2# 2023-1-7, 2023-1-8は土日
3# 2023-1-9は日本では成人の日で祝日だが月曜なので平日判定される
4date_b = ["2023-1-5", "2023-1-6", "2023-1-9", "2023-1-10", "2023-1-11"]
5df_b = pd.DataFrame(data, index=date_b)
6df_b.index = pd.to_datetime(df_b.index)
7print(df_b.index.inferred_freq)
8# "B"

Dと異なり、2B、3Bなどはない。

W:週次(Weekly)

1# 日付間隔が1週間毎、水曜日
2date_1w = ["2020-1-1", "2020-1-8", "2020-1-15", "2020-1-22", "2020-1-29"]
3df_1w = pd.DataFrame(data, index=date_1w)
4df_1w.index = pd.to_datetime(df_1w.index)
5print(df_1w.index.inferred_freq)
6# "W-WED"
7
8# 日付間隔が2週間毎、木曜日
9date_2w = ["2020-1-2", "2020-1-16", "2020-1-30", "2020-2-13", "2020-2-27"]
10df_2w = pd.DataFrame(data, index=date_2w)
11df_2w.index = pd.to_datetime(df_2w.index)
12print(df_2w.index.inferred_freq)
13# "2W-THU"

曜日の情報も付随して返ってくることに注意。

M:月末(Month end)

1# 日付間隔が1ヶ月、月末
2date_m = ["2020-1-31", "2020-2-29", "2020-3-31", "2020-4-30", "2020-5-31"]
3df_m = pd.DataFrame(data, index=date_m)
4df_m.index = pd.to_datetime(df_m.index)
5print(df_m.index.inferred_freq)
6# "M"

月次は月末か月初でないと月次として認識できないことに注意。

月次と四半期はMやQが末日を表し、SがつくとMS、QSで初日を表すことになる。

MS:月初(Month Start)

1# 日付間隔が2ヶ月、月初
2date_2ms = ["2020-1-1", "2020-3-1", "2020-5-1", "2020-7-1", "2020-9-1"]
3df_2ms = pd.DataFrame(data, index=date_2ms)
4df_2ms.index = pd.to_datetime(df_2ms.index)
5print(df_2ms.index.inferred_freq)
6# "2MS"

月次も日次や週次と同じく2M、4Mなどがある。

なお、3Mは四半期なのでQとなる。

BM:月末の平日(Business Month end)

1# 日付間隔が1ヶ月、月末の平日
2# 2022-4-30は土曜日
3date_bm = ["2022-1-31", "2022-2-28", "2022-3-31", "2022-4-29", "2022-5-31"]
4df_bm = pd.DataFrame(data, index=date_bm)
5df_bm.index = pd.to_datetime(df_bm.index)
6print(df_bm.index.inferred_freq)
7# "BM"

BMS:月初の平日(Business Month Start)

1# 日付間隔が1ヶ月、月初の平日
2# 2022-1-2, 2022-5-1は日曜日
3date_bms = ["2022-1-3", "2022-2-1", "2022-3-1", "2022-4-1", "2022-5-2"]
4df_bms = pd.DataFrame(data, index=date_bms)
5df_bms.index = pd.to_datetime(df_bms.index)
6print(df_bms.index.inferred_freq)
7# "BMS"

なおBMS、BMも2BMS、4BMなどを取ることができる。

3BMS、3BMはBQS、BQとなる。

Q:四半期の末日(Quater end)

1# 日付間隔が3ヶ月(四半期)毎、月末
2date_q_nov = ["2020-2-29", "2020-5-31", "2020-8-31", "2020-11-30", "2021-2-28"]
3df_q_nov = pd.DataFrame(data, index=date_q_nov)
4df_q_nov.index = pd.to_datetime(df_q_nov.index)
5print(df_q_nov.index.inferred_freq)
6# "Q-NOV"
7
8# 日付間隔が3ヶ月(四半期)毎、月末
9date_2q_oct = ["2020-1-31", "2020-7-31", "2021-1-31", "2021-7-31", "2022-1-31"]
10df_2q_oct = pd.DataFrame(data, index=date_2q_oct)
11df_2q_oct.index = pd.to_datetime(df_2q_oct.index)
12print(df_2q_oct.index.inferred_freq)
13# "2Q-OCT"

四半期は何月終わりなのかの情報が付加されることに注意。

Q-NOVの例では1月〜12月の終わりの月が11月なのでNOVという情報が付加される。

2Q-OCTの例では、半年毎なので、1月と7月の繰り返しになっているが、間には4月と10月がある。年の終わりの月が10月なのでOCTが付加される。

QS:四半期の初日(Quater start)

1# 日付間隔が3ヶ月(四半期)毎、月初
2date_qs_oct = ["2020-1-1", "2020-4-1", "2020-7-1", "2020-10-1", "2021-1-1"]
3df_qs_oct = pd.DataFrame(data, index=date_qs_oct)
4df_qs_oct.index = pd.to_datetime(df_qs_oct.index)
5print(df_qs_oct.index.inferred_freq)
6# "QS-OCT"

上記の例では1月〜12月のうちの10月で終わっているため、OCTが付加される。

BQ:四半期の平日末日(Business Quater end)

1# 日付間隔が3ヶ月(四半期)毎、月末、平日
2# 2022-12-31は土曜日
3date_bq_dec = ["2022-3-31", "2022-6-30", "2022-9-30", "2022-12-30", "2023-3-31"]
4df_bq_dec = pd.DataFrame(data, index=date_bq_dec)
5df_bq_dec.index = pd.to_datetime(df_bq_dec.index)
6print(df_bq_dec.index.inferred_freq)
7# "BQ-DEC"

BQS:四半期の平日初日(Business Quater Start)

1# 日付間隔が3ヶ月(四半期)毎、月末、平日
2# 2023-1-1、2023-4-2、2023-7-2は日曜日
3date_bq_dec = ["2023-1-2", "2023-4-3", "2023-7-3", "2023-10-1", "2024-1-1"]
4df_bq_dec = pd.DataFrame(data, index=date_bq_dec)
5df_bq_dec.index = pd.to_datetime(df_bq_dec.index)
6print(df_bq_dec.index.inferred_freq)
7# "BQS-OCT"

inferred_freqで頻度の推測ができない例

Pandasの日付Offsetにない頻度は当然推測できないが、一部のOffsetも推測できない。

SM:15日と月末(Semi Month end)

1# 日付間隔が15日と月末
2date_sm = ["2020-1-15", "2020-1-31", "2020-2-15", "2020-2-29", "2020-3-15"]
3df_sm = pd.DataFrame(data, index=date_sm)
4df_sm.index = pd.to_datetime(df_sm.index)
5print(df_sm.index.inferred_freq)
6# None
7
8# (参考)SMで生成される日付
9pd.date_range(start="2020-1-1", periods=5, freq="SM")
10# DatetimeIndex(['2020-01-15', '2020-01-31', '2020-02-15', '2020-02-29', '2020-03-15'],
11#              dtype='datetime64[ns]', freq='SM-15')

SMとなる日付はinferred_freqで頻度を推測できない。

SMS:月初と15日(Semi Month Start)

1# 日付間隔が月初と15日
2date_sms = ["2020-1-1", "2020-1-15", "2020-2-1", "2020-2-15", "2020-3-1"]
3df_sms = pd.DataFrame(data, index=date_sms)
4df_sms.index = pd.to_datetime(df_sms.index)
5print(df_sms.index.inferred_freq)
6# None
7
8# (参考)SMSで生成される日付
9pd.date_range(start="2020-1-1", periods=5, freq="SMS")
10# DatetimeIndex(['2020-01-01', '2020-01-15', '2020-02-01', '2020-02-15', '2020-03-01'],
11#              dtype='datetime64[ns]', freq='SMS-15')

SMと同様にSMSもinferred_freqで頻度推測できない。

Pandas日付Offset以外のパターン

日付Offsetにないパターンは推測できない。

1Dと2Dが混じったパターン

1# 1Dと2Dが混じった場合
2date_1d_2d = ["2020-1-1", "2020-1-2", "2020-1-3", "2020-1-4", "2020-1-6"]
3df_1d_2d = pd.DataFrame(data, index=date_1d_2d)
4df_1d_2d.index = pd.to_datetime(df_1d_2d.index)
5print(df_1d_2d.index.inferred_freq)
6# None

毎月10日

1# 毎月10日
2date_1m = ["2020-1-10", "2020-2-10", "2020-3-10", "2020-4-10", "2020-5-10"]
3df_1m = pd.DataFrame(data, index=date_1m)
4df_1m.index = pd.to_datetime(df_1m.index)
5print(df_1m.index.inferred_freq)
6# None

毎月同じ日付なら月次と判定してほしい気がする所だが、月初か月末でないと推測できない。

まとめ

日次〜四半期単位での、inferred_freqでの推測可否は以下のとおり。

Alias内容inferred_freq
可否
備考
D日次OK2D、3Dなども取れる
7DはWとなる。
B平日OK2B、3Bはない。
W週次OK2W、3Wなども取れる。
W-MONのように曜日情報が付加される。
SM15日と月末NG
SMS月初(1日)と15日NG
M月末OK2M、4Mなども取れる。
3MはQとなる。
MS月初(1日)OK2MS、4MSなども取れる。
3MSはQSとなる。
BM月末の平日OK2BM、4BMなども取れる。
3BMはBQとなる。
BMS月初の平日OK2BMS、4BMSなども取れる。
3BMSはBQSとなる。
Q四半期の末日OK2Q、3Qなども取れる。
Q-OCTのように年の最終四半期が付加される。
QS四半期の初日OK2QS、3QSなども取れる。
年の最終四半期が付加される。
BQ四半期末日の平日OK2BQ、3BQなども取れる。
年の最終四半期が付加される。
BQS四半期初日の平日OK2BQS、3BQSなども取れる。
年の最終四半期が付加される。
スポンサーリンク
ABOUT ME
MAX
MAX
ITエンジニア、データサイエンティスト
新卒でSIerに入社し、フリーランスになってWEB系へ転向。
その後AIの世界へ足を踏み入れ、正社員に戻る。 テーブルデータの分析がメイン。
スポンサーリンク
記事URLをコピーしました