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