LoginSignup
25
31

More than 5 years have passed since last update.

Pythonで書いた移動平均の計算時間を比較してみた

Posted at

前回の記事
MetaTraderのLWMAをscipyのFIRフィルタ関数で実装してみる
で、LWMA(線形加重移動平均)をlfilter()関数で書き換えてみたのですが、すっきりしただけではありがたみがないので、計算時間を比較してみました。

予想としてはそれほど差はないかなと思ったので、移動平均を取る時系列データをちょっと多めにしてみました。以下(自分のブログ記事ですが)を参考にして EUR/USDの1年分の1分足データを読み込んでみました。

PythonでFXヒストリカルデータを読み込む

import numpy as np
import pandas as pd

dataM1 = pd.read_csv('DAT_ASCII_EURUSD_M1_2015.csv', sep=';',
                     names=('Time','Open','High','Low','Close', ''),
                     index_col='Time', parse_dates=True)

始値、高値、安値、終値それぞれ37万個くらいあります。

LWMAの比較

時間を計測するためにJupyter Notebookで、%timeコマンド使ってみました。まずは、LWMAの古い方のバージョン。出力を1個ずつ計算します。

def LWMA(s, ma_period):
    y = pd.Series(0.0, index=s.index)
    for i in range(len(y)):
        if i<ma_period-1: y[i] = 'NaN'
        else:
            y[i] = 0
            for j in range(ma_period):
                y[i] += s[i-j]*(ma_period-j)
            y[i] /= ma_period*(ma_period+1)/2
    return y

%time MA = LWMA(dataM1['Close'], 10)

この結果

Wall time: 3min 35s

なんと3分半も。データが多いと言っても37万個でこんなにかかるとは、Python使えないのか。。。

気を取り直してLWMAの新しいバージョンのテスト。scipyのフィルタ関数を使ったもの。

from scipy.signal import lfilter
def LWMAnew(s, ma_period):
    h = np.arange(ma_period, 0, -1)*2/ma_period/(ma_period+1)
    y = lfilter(h, 1, s)
    y[:ma_period-1] = 'NaN'
    return pd.Series(y, index=s.index)

%time MA = LWMAnew(dataM1['Close'], 10)

この結果

Wall time: 6 ms

なんと!6ミリ秒。35000倍速くなったのか?元が遅すぎるのか。scipy使える。

ちなみに %timeの代わりに%timeitで実行すると、

100 loops, best of 3: 3.4 ms per loop

100回実行しても1秒以内に完了。速いときは3ミリ秒くらいで実行できるらしい。

SMAの比較

scipy速いということで、こんどは、pandasの関数と比較してみました。SMAはpandasのメソッド関数で次のように書けます。

def SMA(s, ma_period):
    return s.rolling(ma_period).mean()

%timeit MA = SMA(dataM1['Close'], 10)

この結果

100 loops, best of 3: 16 ms per loop

100回実行して速くて16ミリ秒。まあまあの速さです。では、これをscipyのフィルタ関数を使って書いてみます。

def SMAnew(s, ma_period):
    h = np.ones(ma_period)/ma_period
    y = lfilter(h, 1, s)
    y[:ma_period-1] = 'NaN'
    return pd.Series(y, index=s.index)

%timeit MA = SMAnew(dataM1['Close'], 10)

この結果

100 loops, best of 3: 3.44 ms per loop

速い。pandasの5倍くらい。やはりscipy速いということで、ほかの移動平均もlfilter()使って書き換えた方がいいかも。

25
31
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
25
31