前回の記事
MetaTraderのLWMAをscipyのFIRフィルタ関数で実装してみる
で、LWMA(線形加重移動平均)をlfilter()
関数で書き換えてみたのですが、すっきりしただけではありがたみがないので、計算時間を比較してみました。
予想としてはそれほど差はないかなと思ったので、移動平均を取る時系列データをちょっと多めにしてみました。以下(自分のブログ記事ですが)を参考にして EUR/USDの1年分の1分足データを読み込んでみました。
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()
使って書き換えた方がいいかも。