[pandas] 時系列インデックスのDataFrameを、月ごとに切り分ける関数を作ってみた (解説付き)

はじめに

以前から、時系列インデックスの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は以下の状態になっています。

4行目時点でのdf

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などでご連絡お待ちしております。

最後までありがとうございました。

PON

PON

30代で、完全未経験から独学でWeb系エンジニアになった人。 前職では、超絶ブラック企業にはまり込んでしまい、年間1200時間の残業をしていたが、娘が生まれたことで我に返って転職を決意。 現在は、大阪にあるベンチャー企業の自社開発プロジェクトで、リードエンジニアとして奮闘中。 主戦場はバックエンドで、Pythonでのデータ分析が武器。 とは言いつつ、SPAのフロントエンドを実装したり、インフラ設計したり、スクラム開発でプロジェクト運営したりするなんでも屋。 いつも、ググってきては誰かが書いてくれた記事を見て開発していたが、もらってばかりでなく世の中に返すこともしたいと思い、技術ブログをはじめる。 妻と1歳になる娘の3人暮らし。 最近は一日一食。 何かご用件がある方は、TwitterのDMからどうぞ。