今回は、日付をインデックスに持つ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