【Pandas】日付インデックスの頻度を判定する
Pandasで時系列データを扱う場合、大抵の場合、インデックスにはDatetimeIndexを使うことになる。
色々な頻度のデータを扱う場合、今扱っているデータの頻度が日次なのか、週次なのかなどの頻度を知りたくなることもある。
DatetimeIndexの生成時にfreqを指定していれば、freqでそのまま頻度を取得できるが、freqが設定されていない場合、Noneが返ってくる。(なおDatetimeIndexは不変なので、生成後に頻度を設定することはできず、インスタンスを再生成することになる)
Noneが返ってきた場合は、日付の間隔などから頻度を推測しても良いが、inferred_freqを使うと頻度を推測して返してくれる。
inferred_freqで頻度の推測が可能な例
基本的にはPandasの日付Offsetで設定されている頻度に合致した場合に、inferred_freqでの推測が可能となる。
ただし、一部の日付Offsetは推測の対象外となっているものもある。
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 | 日次 | OK | 2D、3Dなども取れる 7DはWとなる。 |
B | 平日 | OK | 2B、3Bはない。 |
W | 週次 | OK | 2W、3Wなども取れる。 W-MONのように曜日情報が付加される。 |
SM | 15日と月末 | NG | |
SMS | 月初(1日)と15日 | NG | |
M | 月末 | OK | 2M、4Mなども取れる。 3MはQとなる。 |
MS | 月初(1日) | OK | 2MS、4MSなども取れる。 3MSはQSとなる。 |
BM | 月末の平日 | OK | 2BM、4BMなども取れる。 3BMはBQとなる。 |
BMS | 月初の平日 | OK | 2BMS、4BMSなども取れる。 3BMSはBQSとなる。 |
Q | 四半期の末日 | OK | 2Q、3Qなども取れる。 Q-OCTのように年の最終四半期が付加される。 |
QS | 四半期の初日 | OK | 2QS、3QSなども取れる。 年の最終四半期が付加される。 |
BQ | 四半期末日の平日 | OK | 2BQ、3BQなども取れる。 年の最終四半期が付加される。 |
BQS | 四半期初日の平日 | OK | 2BQS、3BQSなども取れる。 年の最終四半期が付加される。 |