今回は、日付をインデックスに持つpandasのデータをシフトする方法、つまりデータを時間的に前方または後方へ移動させる方法を紹介する。

shiftメソッドの基本的な使い方

まずは例として、以下のようなシリーズを用意する。

import pandas as pd
import numpy as np

ts = pd.Series(np.random.randn(4),
              index=pd.date_range('2019/10/01', periods=4, freq='M'))

# 2019-10-31    0.793998
# 2019-11-30    1.319637
# 2019-12-31   -1.013920
# 2020-01-31   -0.051344
# Freq: M, dtype: float64

以下がshiftメソッドを利用した、データシフトの例だ。

ts.shift(2)
# 2019-10-31         NaN
# 2019-11-30         NaN
# 2019-12-31   -0.260256
# 2020-01-31    0.778421
# Freq: M, dtype: float64

ts.shift(-2)
# 2019-10-31    0.434772
# 2019-11-30   -1.230228
# 2019-12-31         NaN
# 2020-01-31         NaN
# Freq: M, dtype: float64

引数に指定した値の分だけ、データを前後にシフトさせることができる。

ただし、このままではデータをシフトした分、前後に欠損値が生じてしまう。

これを防ぐ場合は、freqオプションに頻度を指定すれば良い。

ts.shift(-2, freq='M')
# 2019-08-31   -0.260256
# 2019-09-30    0.778421
# 2019-10-31    0.434772
# 2019-11-30   -1.230228
# Freq: M, dtype: float64

なお、元データの頻度と違う頻度を指定することもでき、より柔軟にシフトを変化させることができる。

ts.shift(-2, freq='D')
# 2019-10-29   -0.260256
# 2019-11-28    0.778421
# 2019-12-29    0.434772
# 2020-01-29   -1.230228
# dtype: float64

オフセットを利用した日付シフトの方法

次は、pandasの日付オフセットを利用して、日付をシフトする例を見ていく。

以下は、オフセットのDay、MonthEndを用いてタイムスタンプをシフトする例だ。

import datetime
from pandas.tseries.offsets import Day, MonthEnd

now = datetime.date(2019, 10, 13)

# 3日進める
now + Day(3)
# Timestamp('2019-10-16 00:00:00')

# 月の最終日まで進める
now + MonthEnd()
# Timestamp('2019-10-31 00:00:00')

日付オフセットの便利な使い方

日付オフセットはgroupbyメソッドと合わせて使う便利な方法があるので、一例を以下に示しておく。

import datetime
from pandas.tseries.offsets import Day, MonthEnd
import pandas as pd
import numpy as np

offset = MonthEnd()

ts = pd.Series(np.random.randn(10), 
              index=pd.date_range('2019/10/01', periods=10, freq='10d'))
# 2019-10-01   -1.288469
# 2019-10-11   -0.548288
# 2019-10-21    0.461845
# 2019-10-31   -0.878449
# 2019-11-10   -0.277805
# 2019-11-20   -0.207038
# 2019-11-30   -1.511350
# 2019-12-10   -0.265582
# 2019-12-20    0.096316
# 2019-12-30   -0.198821
# Freq: 10D, dtype: float64

ts.groupby(offset.rollforward).mean()
# 2019-10-31   -0.563340
# 2019-11-30   -0.665398
# 2019-12-31   -0.122696
# dtype: float64

なお、上記と同じ処理をresampleメソッドで簡潔に書くこともできる。

ts.resample('M').mean()
# 2019-10-31   -0.563340
# 2019-11-30   -0.665398
# 2019-12-31   -0.122696
# Freq: M, dtype: float64