はじめに
以前から、時系列インデックスのDataFrameを月ごとに切り分けて、それをループさせたいという事が多々ありました。
groupby
メソッド等を使ってできなくもないのですが、そもそもgroupbyは集計を目的としたメソッドということもあり、変にオブジェクト型として持ち回す必要があったりして、どうも実装しにくい。
ということで、勉強も兼ねて実装してみました。
何かの参考にしていただけると嬉しいです。
動作確認ができる今日の結論コード
下の実行ボタンから、動作確認ができます。
コードを変更して実行することもできるので、いじってみて下さい。
解説
関数全体の様子
def get_monthly_df_list(df: pd.DataFrame) -> List[pd.DataFrame]:
# マルチインデックス化
multi_idx_df = df.set_index([df.index.year, df.index.month, df.index])
multi_idx_df.index.names = ['year', 'month', '']
# 時系列インデックスの先頭の日付を取得
start_date = multi_idx_df.index[0][-1]
end_date = multi_idx_df.index[-1][-1]
df_in_list = []
target_date = start_date
while target_date.replace(day=1) <= end_date.replace(day=1):
# 月ごとにdfを切り分けて、リストに格納していく
monthly_df = multi_idx_df.loc[(target_date.year, target_date.month)]
df_in_list.append(monthly_df)
# 1ヶ月加算して次のループへ
target_date += relativedelta(months=1)
return df_in_list
4行目 : マルチインデックス化
今回、DataFrameを月ごとに切り分ける方法として、マルチインデックスを使いました。
4行目の時点で、DataFrameは以下の状態になっています。

7行目 : start_dateとend_dateの準備
そして、7行目付近でこのDataFrameの先頭と末尾の日にちを取得しています。
サンプルコードの場合、start_dateには2020-01-31が、end_dateには2020-04-01がそれぞれ代入されています。
13行目 : start_dateから1ヶ月ずつ加算しながらループ
target_dateにstart_dateを代入して、ループ!
毎周、target_dateに1ヶ月ずつ加算していって、end_dateを超えるまでループ!
このループの中で、月ごとにdfを切り分けていって、リストに格納していきます。
応用アイデア
今回は月ごとに切り分ける実装ですが、この時系列マルチインデックスは週単位や四半期単位につけることも可能です。
つまり、週ごとや四半期ごとにDataFrameを切り分けてリスト化するなんてことも簡単にできるかと思います。
必要な方は、是非お試し下さい。
さいごに
今日は、時系列インデックスのDataFrameを月ごとに切り分ける関数を作って、その解説を記事にしました。
何かツッコミがあれば、Twitterなどでご連絡お待ちしております。
最後までありがとうございました。