【Python】pandas DataFrameによる指数荷重計算(EMA)
pythonのデータフレームには指数荷重(exponential weighted)計算を行うことができるewmというメソッドがあります。これを使用することで、株価のテクニカルの指標の計算などにも使用することができます。
今回はewmメソッドの使い方について以下のサイトを参考にしながら調べていきます。
pandas.DataFrame.ewm — pandas 2.2.2 documentation (pydata.org)
使い方の例
まず、ewmはこのような形で使うことができます。
import pandas as pd
import numpy as np
a = [1, 2, 3, np.nan, 5, 6]
df = pd.DataFrame(a)
df.head(6)
結果:
0
0 1.0
1 2.0
2 3.0
3 NaN
4 5.0
5 6.0
指数荷重計算の例
df.ewm(com=2).mean()
結果:
0
0 1.000000
1 1.600000
2 2.263158
3 2.263158
4 3.675159
5 4.689408
このようにewmを用いることで過去の値に重みづけしながら現在のインデックスの値を計算します。
以下で、オプションパラメータの設定による計算方法の違いについて説明します。
平滑化係数(alpha)
平滑化係数である\(\alpha\)を計算する方法としてはewmのオプションにcom, span, hallifeをそれぞれ設定することで異なる計算式で求めることが可能です。
comを使用する場合
\(\alpha = \frac{1}{1+com}\) となります。comは0以上の値を設定します。
例:
df.ewm(com=4).mean()
結果:
0
0 1.000000
1 1.555556
2 2.147541
3 2.147541
4 3.261087
5 4.159303
spanを使用する場合
\(\alpha = \frac{2}{1+span}\)となります。spanは0以上の値を設定します。
例:
df.ewm(span=4).mean()
結果:
0
0 1.000000
1 1.625000
2 2.326531
3 2.326531
4 3.893996
5 4.934841
hallifeを使用する場合
\(\alpha =1 – \exp(\frac{-\ln{2}}{halflife})\)
df.ewm(halflife=4).mean()
結果:
0
0 1.000000
1 1.543214
2 2.114950
3 2.114950
4 3.144696
5 3.995515
平滑化平均の計算方法(adjutst)
指数加重平均の計算結果である\(y_t\)を、求める方法に減衰を加えて調整するかしないかを選択することができます。デフォルトは調整する(adjust=True)となっています。
adjust=Trueの場合
\(y_t = \frac{x_t+(1-\alpha)x_{t-1}+(1-\alpha^2)x_{t-2}…+(1-\alpha)^tx_0}{1+(1-\alpha)+(1-\alpha)^2+…+(1-\alpha)^t}\)
df.ewm(span=4, adjust=True).mean()
結果:
0
0 1.000000
1 1.625000
2 2.326531
3 2.326531
4 3.893996
5 4.934841
adjust=Flaseの場合
adjus=Falseとした場合はよりシンプルな以下の計算となります。
\( y_t = (1-\alpha)y_{t-1} + \alpha x_t \)
ここで、\(y_0 = x_0\)です。
df.ewm(span=4, adjust=False).mean()
0
0 1.000000
1 1.400000
2 2.040000
3 2.040000
4 3.597895
5 4.558737
欠損値の扱い(ignore_na)
ignore_naのオプションを設定することでデータの中に欠損値が含まれていた場合の処理に違いを制御することができます。
以下のデータを例に説明していきます。
a = [1, np.nan,2]
df = pd.DataFrame(a)
df.head()
結果:
0
0 1.0
1 NaN
2 2.0
ignore_na=Falseとした場合
各インデックスの絶対位置に基づいて重みが計算されます。つまり、インデックス1のNaNのデータには関係なく、重み計算が行われます。わかりやすくαの値を固定した以下のコードで確認してみます。comやspanなどのかわりにalphaオプションを設定することでalphaを直接決めることができます。
df.ewm(alpha=0.2, adjust=False, ignore_na=False).mean()
結果:
0
0 1.000000
1 1.000000
2 1.238095
計算式を考えてみると、インデックス0についてはもともとの入力\(x_0\)をそのまま返し、データの存在しないインデックス1については、現在の値がないので、前の結果を出力します。
\(y_0 = x_0 = 1 \)
\(y_1 = y_1 \)
重要なのはインデックス2の計算になります。まず、adjust=Falseの通常の式は次のようになります。
\(y_2 = (1-\alpha)^2 x_0 +\alpha(1-\alpha)x_1 +\alpha \times x_2 \)
この時、\(x_1\)であるため、使用する重みは \((1-\alpha)^2と \alpha \)とするのが、ignore_na=Falseのオプションです。
ただし、全体で100%になるように重みづけをする必要があるため、以下のような式になります。
\(y_2 = \frac{(1-\alpha)^2}{(1-\alpha)^2+\alpha} x_0 + \frac{\alpha}{(1-\alpha)^2+\alpha} x_2 \)
そのため、今回の例では次のようにインデックス2の結果が計算されています。
\(y_2 = \frac{(1-0.2)^2}{(1-0.2)^2+0.2} \times 1 + \frac{0.2}{(1-0.2)^2+0.2} \times 2 = \frac{0.64}{0.84} + \frac{0.4}{0.84}=1.238095 \)
ignore_na=Trueとした場合
この場合にはNaNを無視して相対位置で重み計算が行われるため、\(y_2\)の計算式は次のようになります。
\(y_2 = (1-\alpha) x_0 + \alpha x_2 = 0.8 \times 1 +0.2 \times 2 = 1.2\)
プログラムで確認すると以下のようになります。
df.ewm(alpha=0.2, adjust=False, ignore_na=True).mean()
結果:
0
0 1.0
1 1.0
2 1.2
まとめ
Pandasで指数加重平均の計算を行うことができました。また、オプションを設定することで、重みのパラメータalphaや欠損値があった場合の処理なども指定することが可能です。株価のテクニカル分析などの際に役に立ちます。