Эту задачу довольно сложно эффективно векторизовать Numpy. В вашей версии у вас есть векторизованная команда, которая выполняет итерацию по значениям, которые не хранятся в памяти непрерывно Numpy / C мажор строки, Fortran / Matlab / Julia - мажор столбца.
Если вы хотите использовать Numpy, вероятно, самый простой способ - это транспонировать все массивы и операции или использовать массивы, упорядоченные по Фортрану (должен давать коэффициент 4).
Другой способ - записать циклы и сделать использование Numba Numba или Cython .
Numba Пример
@nb.njit(fastmath=True,parallel=True,cache=True)
def Numba(Z0,Y0,sigma_Y,sigma_Z,Wt_1,Wt_2,rho,dt):
N,M=Wt_1.shape
Z=np.empty((M,N+1))
Y=np.empty((M,N+1))
Z[:,0]=Z0
Y[:,0]=Y0
#the possibillity of negative values can lead to a slow wrap-around check
for i in nb.prange(M):
#only beneficial for very large
for j in range(N):
Z[i,j+1]=Z[i,j] - 0.5*(sigma_Z**2)*dt + sigma_Z*np.sqrt(dt)*Wt_1[i,j]
Y[i,j+1]=Y[i,j] + sigma_Y*np.sqrt(dt)* (rho*Wt_1[i,j] + np.sqrt(1 - rho**2)*Wt_2[i,j])
return Z,Y
Ваш Numpy пример
Также было бы неплохо добавить пример того, как вы получили свои тайминги, поскольку генерация входных данных занимает больше времени, чем фактическое вычисление (по крайней мере, для версии Numba).
def Numpy_not_aligned(Z0,Y0,sigma_Y,sigma_Z,Wt_1,Wt_2,rho,dt):
Z=np.zeros((M,N+1))
# shape is (100 000, 5 001)
Y=np.zeros((M,N+1))
#in SciPy indexing starts from 0 :
Z[:,0]=Z0
Y[:,0]=Y0
for i in range(1,N+1) :
Z[:,i]=Z[:,i-1] - 0.5*(sigma_Z**2)*dt + sigma_Z*np.sqrt(dt)*Wt_1[:,i-1]
Y[:,i]=Y[:,i-1] + sigma_Y*np.sqrt(dt)* (rho*Wt_1[:,i-1] + np.sqrt(1 - rho**2)*Wt_2[:,i-1])
return Y,Z
Время
# M=M=50000
%timeit Numpy_not_aligned(Z0,Y0,sigma_Y,sigma_Z,Wt_1,Wt_2,rho,dt)
#25.9 s ± 82.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit Numba(Z0,Y0,sigma_Y,sigma_Z,Wt_1,Wt_2,rho,dt)
#1.03 s ± 127 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)