PythonコードをNumbaで高速化したときのメモ
の続きというか、補足です。
pandasは時系列データの処理に便利なのですが、そのままfor文を使うと極端に遅くなります。
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)
def LWMA(s, ma_period):
y = pd.Series(0.0, index=s.index)
for i in range(len(y)):
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 10s
データ数が37万個と多いのですが、10サンプルの移動平均で3分かかるのは厳しいです。期間をもっと長くすると、10分以上かかることもあります。(Core i7-6700 3.4GHz)
前回の記事では、arrayに置き換えてNumbaを使って高速化してみましたが、実際、arrayにするだけでも高速になります。
def LWMA1(s, ma_period):
a = s.values
y = np.zeros(len(a))
for i in range(len(y)):
for j in range(ma_period):
y[i] += a[i-j]*(ma_period-j)
y[i] /= ma_period*(ma_period+1)/2
return pd.Series(y, index=s.index)
%timeit MA = LWMA1(dataM1['Close'], 10)
1 loop, best of 3: 1.92 s per loop
Numbaを使わなくても、pandasに比べると、100倍くらい速くなっています。
もちろんこの状態だと、Numbaを使うともっと速くなります。
from numba import jit
@jit
def LWMA2(s, ma_period):
a = s.values
y = np.zeros(len(a))
for i in range(len(y)):
for j in range(ma_period):
y[i] += a[i-j]*(ma_period-j)
y[i] /= ma_period*(ma_period+1)/2
return pd.Series(y, index=s.index)
%timeit MA = LWMA2(dataM1['Close'], 10)
100 loops, best of 3: 5.31 ms per loop
pandasでfor文を使う場合でも、arrayに置き換えられるケース(indexが関係ないケース)であれば、そうすることが賢明です。pandasとうまくつきあうには、ちょっとしたコツが必要なようです。