📆

PythonのDataFrameで日付を取り扱う

2023/10/15に公開

pandasで時系列データを取り扱った際の気付き諸々をまとめていく。(随時更新予定)

1. pandas DataFrameで日付データをDatetime indexとして取り扱う

日付ベースのデータをもとに集計する場合は、日付データをDatetime indexとして取り扱った方が何かと便利と思われる。

1.1. 利点 Group_byによる集計が簡単

たとえば月次/四半期での集計は pd.Grouper(freq='param') を用いて実施できる。

import pandas as pd
import numpy as np
from datetime import date

# `pd.date_range`で2022年1年分の日付を作成。

pd_dates = pd.date_range(start='2022-01-01', end='2022-12-31')

np.random.seed(100)
df_pd = pd.DataFrame(
    np.random.randint(1, 100, len(pd_dates)), index=pd_dates, columns=['count']
    )

# 月次集計
monthly_mean = df_pd.groupby(pd.Grouper(freq='M')).mean()
# 四半期集計
quarterly_mean = df_pd.groupby(pd.Grouper(freq='Q')).mean()

上記コードの出力例:

# monthly_mean=月次集計の出力

|        | count     |
| ---------- | --------- |
| 2022-01-31 | 44.806452 |
| 2022-02-28 | 51.214286 |
| 2022-03-31 | 50.225806 |
| 2022-04-30 | 53.100000 |
| 2022-05-31 | 48.419355 |
| 2022-06-30 | 52.133333 |
| 2022-07-31 | 48.322581 |
| 2022-08-31 | 54.774194 |
| 2022-09-30 | 52.000000 |
| 2022-10-31 | 47.096774 |
| 2022-11-30 | 49.800000 |
| 2022-12-31 | 50.322581 |
quarterly_mean=四半期集計の出力。

|        | count     |
| ---------- | --------- |
| 2022-03-31 | 48.666667 |
| 2022-06-30 | 51.186813 |
| 2022-09-30 | 51.695652 |
| 2022-12-31 | 49.065217 |

ちなみに、 resample でもおなじ集計が可能。

pandas.DataFrame.resample

1.2. チョット欠点

上記の出力を見て解るように、集計後のDatetimeIndexはグループの「末日」が表記される。
「末尾まで集計した」と理解すれば解りやすいとも言えるが直感的ではない。

1.3. 改善案

これでは、意味が捉えにくいこともあるので、 pd.PeriodIndexstrftime を用いてpd.indexを月次or四半期の表記に変更する。
グラフ化やテーブル出力する際にはこの形でHuman Readableにしておくほうがよい。

monthly_mean.index = pd.PeriodIndex(monthly_mean.index).strftime('%Y-%m')

quarterly_mean.index = pd.PeriodIndex(quarterly_mean.index).strftime('%Y-Q%q')
|      |     count|
| ---- | --- |
| 2022-01 | 44.806452 |
| 2022-02 | 51.214286 |
| 2022-03 | 50.225806 |
| 2022-04 | 53.100000 |
| 2022-05 | 48.419355 |
| 2022-06 | 52.133333 |
| 2022-07 | 48.322581 |
| 2022-08 | 54.774194 |
| 2022-09 | 52.000000 |
| 2022-10 | 47.096774 |
| 2022-11 | 49.800000 |
| 2022-12 | 50.322581 |
|      |     count|
| ---- | --- |
| 2022-Q1 | 48.666667 |
| 2022-Q2 | 51.186813 |
| 2022-Q3 | 51.695652 |
| 2022-Q4 | 49.065217 |

2. PeriodIndexの応用:会計年度(fiscal year)と四半期を表示する方法

日本企業だけでなく、会社のデータを集計する場合は何かと「会計年度」「決算年度」「四半期」での集計がもとめられる。
PeriodIndexfreq オプションを使うと日付を「年度」に変更できる。

上記とは少々違う事例で試してみる。

df = pd.DataFrame({
        'date': ['2022-01-01', '2023-04-01', '2024-07-01', '2025-12-01']
    })

df['date'] = pd.to_datetime(df['date'])
  • 3月を期末として年度を取得する方法: freqA-MAR を設定して1を引く(理由は後述)
  • 3月を期末として設定した年度の四半期を取得する方法: freqQ-MAR を設定する

具体的なコードと出力:

df['fiscal_year'] = (pd.PeriodIndex(df['date'], freq='A-MAR') - 1).strftime('FY%Y')

df['fy_quarter'] = (pd.PeriodIndex(df['date'], freq='Q-MAR')).strftime('Q%q')

print(df)
# 上記コードの出力
        date fiscal_year fy_quarter
0 2022-01-01      FY2021         Q4
1 2023-04-01      FY2023         Q1
2 2024-07-01      FY2024         Q2
3 2025-12-01      FY2025         Q3

1を除算する理由

pd.PeriodIndex(df['date'], freq='A-MAR') の出力は以下となる。

# 上記コードの出力

PeriodIndex(['2022', '2024', '2025', '2026'], dtype='period[A-MAR]', name='date')

df['date']['2022-01-01', '2023-04-01', '2024-07-01', '2025-12-01'] である。
これを処理した際の期待する出力は ['2021', '2023', '2024', '2023'] だが、実際には ['2022', '2024', '2025', '2026'] が出力される。
これは、PeriodIndexの処理 [1] がMARを最終月とした年次、すなわち4月に次の年次が開始する処理をしているしているためである。
期待する「年度」を出力するためには、1を除算して解決する。

3. 参考としたサイト

脚注
  1. PeriodIndexはarray-likeデータを引数にとって PeriodIndex オブジェクトを返す。 ↩︎

Discussion