Pandas.Series.shift: データフレームのシフト操作をマスターしよう


Pandas.Series.shift: データフレームのシフト操作をマスターしよう

基本的な使い方

import pandas as pd

# サンプルデータを作成
s = pd.Series([1, 2, 3, 4, 5], index=pd.date_range('2020-01-01', periods=5))

# 1期間過去にシフト
shifted_s = s.shift(1)

print(shifted_s)

このコードを実行すると、以下の出力が得られます。

Output:

2020-01-02    NaN
2020-01-03    1.0
2020-01-04    2.0
2020-01-05    3.0
2020-01-06    4.0
Freq: D
dtype: float64

解説

  • s.shift(1) は、s の値を1期間過去にシフトします。
  • シフトされたデータは新しい Series として格納されます。
  • 最初の要素は NaN になります。これは、過去にデータが存在しないためです。
  • インデックスは元の Series と同じままです。

オプション引数

  • periods: シフトする期間を指定します。正の値で過去に、負の値で未来にシフトします。デフォルトは1です。
  • fill_value: シフトによって生じる欠損値を埋める値を指定します。デフォルトは NaN です。
  • freq: 時系列データの周波数を指定します。これは、インデックスをどのようにシフトするかを決定するために使用されます。デフォルトは None です。

応用例

  • 移動平均線の計算
  • トレンド分析
  • 相関分析
  • 季節性の分析
  • axis 引数を使用して、シフト方向を指定することもできます。デフォルトは0(行方向)です。
  • periods 引数にリストを渡すと、複数の期間にわたってシフトできます。


import pandas as pd

# サンプルデータを作成
s = pd.Series([1, 2, 3, 4, 5, 6], index=pd.date_range('2020-01-01', periods=6))

# 3期間移動平均線
ma3 = s.shift(1).add(s.shift(2)).add(s) / 3

print(ma3)

このコードは、s の3期間移動平均線を計算します。

  • s.shift(1).add(s.shift(2)).add(s) は、シフトされた値をすべて足します。
  • / 3 で3で割ることで、移動平均線の値を求めます。

トレンド分析

import pandas as pd

# サンプルデータを作成
s = pd.Series([10, 15, 20, 25, 30], index=pd.date_range('2020-01-01', periods=5))

# 1期間過去のデータとの差分
diff = s - s.shift(1)

print(diff)

このコードは、s のトレンドを分析します。

  • s - s.shift(1) は、s の値と1期間過去の値の差を求めます。
  • 正の値は増加、負の値は減少を表します。

相関分析

import pandas as pd

# サンプルデータを作成
s1 = pd.Series([1, 2, 3, 4, 5], index=pd.date_range('2020-01-01', periods=5))
s2 = pd.Series([10, 20, 30, 40, 50], index=pd.date_range('2020-01-01', periods=5))

# シフトして相関関係を計算
corr = s1.corr(s2.shift(-1))

print(corr)

このコードは、s1s2 の間の相関関係を分析します。

  • s1.corr(s2.shift(-1)) は、シフトされた s2s1 の相関関係を計算します。

季節性の分析

import pandas as pd

# サンプルデータを作成
s = pd.Series([12, 14, 15, 13, 12, 14, 15, 13], index=pd.to_datetime(['2020-01-01', '2020-02-01', ..., '2020-08-01']))

# 季節性を抽出
seasonal = s - s.shift(12)

print(seasonal)
  • 季節的な変動はこの差に現れます。
  • 上記のコードはあくまで一例です。ご自身のデータに合わせて、自由にカスタマイズしてください。


Pandas.Series.shift の代替方法

diff() と fillna() を使用する

import pandas as pd

# サンプルデータを作成
s = pd.Series([1, 2, 3, 4, 5], index=pd.date_range('2020-01-01', periods=5))

# 1期間過去のデータとの差分
diff = s.diff()

# 最初の欠損値を埋める
filled_diff = diff.fillna(method='ffill')

print(filled_diff)

説明:

このコードは、diff()fillna() を組み合わせて、pandas.Series.shift と同様の操作を行います。

  1. fillna(method='ffill') は、最初の欠損値を前の値で埋めます。

利点:

  • シンプルで分かりやすいコードです。
  • 欠損値の処理方法を柔軟に制御できます。

欠点:

  • pandas.Series.shift よりも処理速度が遅い場合があります。

rolling() と apply() を使用する

import pandas as pd

# サンプルデータを作成
s = pd.Series([1, 2, 3, 4, 5], index=pd.date_range('2020-01-01', periods=5))

# 1期間過去のデータを取得
def lag(series, n):
    return series.shift(n)

shifted_s = s.rolling(window=1).apply(lag, args=(1,))

print(shifted_s)
  1. rolling(window=1) は、1要素のウィンドウを作成します。
  2. apply(lag, args=(1,)) は、各ウィンドウに対して lag 関数を適用します。
  3. lag 関数は、引数で指定された期間だけシフトした値を返します。
  • 柔軟性が高く、様々な操作に適用できます。
  • コードが複雑になる場合があります。

index 操作を利用する

import pandas as pd

# サンプルデータを作成
s = pd.Series([1, 2, 3, 4, 5], index=pd.date_range('2020-01-01', periods=5))

# 1期間過去のインデックスを作成
shifted_index = s.index - pd.DateOffset(days=1)

# 1期間過去のデータを取得
shifted_s = s.reindex(shifted_index)

print(shifted_s)

このコードは、インデックス操作を利用して、pandas.Series.shift と同様の操作を行います。

  1. pd.DateOffset(days=1) は、1日前の日付を表すオフセットを作成します。
  2. s.index - pd.DateOffset(days=1) は、1期間過去のインデックスを作成します。
  3. s.reindex(shifted_index) は、s を1期間過去のインデックスに再インデックスします。
  • 欠損値の処理ができません。
  • 上記以外にも、状況によっては他の方法が考えられます。