2016-05-25 21 views
1

N_MCシミュレーションの株価Sのパスは、最初のポイントを除く各パスにnとなります。これを行うためのアルゴリズムは、与えられた経路について、株価の以前の値に対して再帰的である。ここで私は今持っているものです。効率的な再帰的乗法

import numpy as np 
import time 

N_MC = 1000 
n = 10000 

S = np.zeros((N_MC, n+1)) 
S0 = 1.0 
S[:, 0] = S0 

start_time_normals = time.clock() 
Z = np.exp(np.random.normal(size=(N_MC, n))) 
print "generate normals time = ", time.clock() - start_time_normals 

start_time_prices = time.clock() 
for i in xrange(N_MC): 
    for j in xrange(1, n+1): 
     S[i, j] = S[i, j-1]*Z[i, j-1] 

print "pices time = ", time.clock() - start_time_prices 

回であった:

generate normals time = 1.07 
pices time = 9.98 

は、おそらくnumpyののルーチンを使用して、配列Sを生成するために、はるかに効率的な方法はありますか?通常のランダム変数Zがより速く生成されてもいいですが、私はうまくいきません。

+0

「cumsum」と「cumprod」は、i番目の値が「i-1th」に依存するとき便利な関数です。それらから計算を構築することができます。 'ufunc'' accumulate'メソッドも見てください。 – hpaulj

答えて

4

「パス」は互いに独立しているため、ループする必要はありません。したがって、外側のループfor i in xrange(N_MC)を削除して、SZという列全体を操作するだけです。

再帰的計算を高速化するために、単一の「パス」を考えてみましょう。 zは、タイムスタンプごとにランダムな値を含むベクトルです(すべての時間は既知です)。 sは、各タイムステップで出力を含むべきベクトルです。 s0は時間ゼロでの初期出力です。 jは時間です。

あなたのコードでは、再帰的に出力に含まを定義しています

s[j] = s[j-1]*z[j-1] 

だが、これを拡張してみましょう:

s[1] = s[0]*z[0] 

s[2] = s[1]*z[1] 
    = s[0]*z[0]*z[1] 

s[3] = s[2]*z[2] 
    = s[0]*z[0]*z[1]*z[2] 

s[4] = s[3]*z[3] 
    = s[0]*z[0]*z[1]*z[2]*z[3] 

各出力s[j]が0からj-1にランダムな値のs[0]倍積で与えられます。あなたは、はるかに効率的にループよりもあるべきnumpy.cumprod()を使用して、このような累積積を計算することができます

s = np.concatenate(([s0], s0 * np.cumprod(z[0:-1]))) 

あなたは行列の一つの次元に沿って操作するためのaxisパラメータを使用することができます(パス」の両端に並列にこれを行うための例を')。

+0

ありがとう!最後の行に 'axis'パラメータを使って何を意味するのか説明してください。おそらくネストされた 'np.concatenate'sを使って、これをすべて1行で実行できると言っていますか? – bcf

+0

パスをループする必要がないという最初の点を組み合わせると、 'cumprod()'ソリューションを一般化して、すべての行を同時に処理することができます。これにより、行列を使って作業しながら、データセット全体を一度に生成することができます。この場合、 'cumprod()'の 'axis'パラメータを使って、乗算する行列の次元を指定します。 – user20160

+0

入手しました。私は驚くほど速く、すべてのパスをループすることがわかった。 – bcf