LoginSignup
31
27

More than 5 years have passed since last update.

Pythonで書いた指数移動平均(EMA)のコードの比較

Posted at

移動平均のなかで、単純移動平均(SMA)の次によく使われるのは指数移動平均(EMA)でしょう。EMAを使うテクニカル指標として有名なMACDをはじめ、EMAを複数回使うDEMA、TEMA、TriXというのもあるし、AMA、FrAMA、VIDyAのように適応型移動平均は、計算方法としてEMAを利用しています。

今回は、
IIRフィルタ型の移動平均をpandasとscipyで比較してみた
の続きとして、EMAのコードをいくつか比較してみます。

EMAの計算式

EMAを実際に使う際には期間をパラメータとして入れますが、ここではEMA本体のパフォーマンスを調べるために計算式を直接使います。

$$y(n)=\alpha x(n)+(1-\alpha)y(n-1)$$

つまり、EMAのパラメータは上式の$\alpha$とします。

pandasによる実装

まず、EMAをかける入力データを
Numba使用を前提とした単純移動平均のPythonコードについて
と同じくランダムウォークとして作っておきます。

import numpy as np
import pandas as pd

dn = np.random.randint(2, size=100000)*2-1
gwalk = np.cumprod(np.exp(dn*0.01))*100

pandasでは、Seriesクラスに変換してewmmeanメソッドで簡単にEMAを実行できます。ewmのパラメータとしてalphaを直接代入することもできます。alphaは0から1の範囲で特に値による違いはないので、ここでは0.15を入れておきます。

def EMA1(x, alpha):
    return pd.Series(x).ewm(alpha=alpha).mean()

%timeit y1 = EMA1(gwalk, 0.15)

実行時間は以下の通りです。

100 loops, best of 3: 8.62 ms per loop

scipyのlflterによる実装

IIRフィルタ型の移動平均をpandasとscipyで比較してみた
と同じようにscipyのフィルタ関数lfilterを使った実装です。

from scipy.signal import lfilter
def EMA2(x, alpha):
    y,zf = lfilter([alpha], [1,alpha-1], x, zi=[x[0]*(1-alpha)])
    return y

%timeit y2 = EMA2(gwalk, 0.15)

実行時間は次のようになりました。

1000 loops, best of 3: 631 µs per loop

前回の記事はここまでで、scipy速いということだったのですが、今回は続きがあります。

Numbaを利用した計算式の直接実装

EMAの計算式を直接コーディングします。ただし、そのままだとすごく遅くなるので、Numbaを使って高速化します。

from numba import jit
@jit(nopython=True)
def EMA3(x, alpha):
    y = np.empty_like(x)
    y[0] = x[0]
    for i in range(1,len(x)):
        y[i] = alpha*x[i] + (1-alpha)*y[i-1]
    return y

%timeit y3 = EMA3(gwalk, 0.15)

@jitの引数にnopython=Trueをつけてエラーが出なければ高速化が期待できます。実際、実行時間は

1000 loops, best of 3: 227 µs per loop

となり、scipyより速くなりました。

EMAの場合も、Numbaを使えば直接コーディングが最速という結果となりました。

31
27
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
31
27