以递归方式生成5百万个点r[i]
:
import numpy as np
n, a, b, c = 5000000, 0.0000002, 0.5, 0.4
eps = np.random.normal(0, 1, n)
sigma = np.ones(n) * np.sqrt(a)
r = np.zeros(n)
for i in range(1,n):
sigma[i] = np.sqrt(a + b * r[i-1] ** 2 + c * sigma[i-1] ** 2)
r[i] = sigma[i] * eps[i]
在我的标准i5笔记本电脑上使用大约17秒。
过去我经常使用Cython,我知道在这里使用它可能会优化10倍<10倍。 k&lt; 100。
但是在这种情况下不得不使用Cython之前,我想知道:是否会有一个简单的Numpy / Python方法,我不知道会对此进行优化?
答案 0 :(得分:2)
只需将其更改为math.sqrt
而非np.sqrt
,即可获得约40%的加速。
因为我是一个非常狂热的狂热分子,所以我尝试了numba版本与你的版本(initial
)和数学版本(normal
)
import numpy as np
import math
import numba as nb
n, a, b, c = 500000, 0.0000002, 0.5, 0.4
eps = np.random.normal(0, 1, n)
sigma = np.ones(n) * np.sqrt(a)
r = np.zeros(n)
def initial(n, a, b, c, eps, sigma, r):
for i in range(1,n):
sigma[i] = np.sqrt(a + b * r[i-1] ** 2 + c * sigma[i-1] ** 2)
r[i] = sigma[i] * eps[i]
def normal(n, a, b, c, eps, sigma, r):
for i in range(1,n):
sigma[i] = math.sqrt(a + b * r[i-1] ** 2 + c * sigma[i-1] ** 2)
r[i] = sigma[i] * eps[i]
@nb.njit
def function(n, a, b, c, eps, sigma, r):
for i in range(1,n):
sigma[i] = math.sqrt(a + b * r[i-1] ** 2 + c * sigma[i-1] ** 2)
r[i] = sigma[i] * eps[i]
然后只是为了验证结果是否相同:
sigma1 = sigma.copy()
sigma2 = sigma.copy()
sigma3 = sigma.copy()
r1 = r.copy()
r2 = r.copy()
r3 = r.copy()
initial(n, a, b, c, eps, sigma1, r1)
normal(n, a, b, c, eps, sigma2, r2)
function(n, a, b, c, eps, sigma3, r3)
np.testing.assert_array_almost_equal(sigma1, sigma2)
np.testing.assert_array_almost_equal(sigma1, sigma3)
np.testing.assert_array_almost_equal(r1, r2)
np.testing.assert_array_almost_equal(r1, r3)
那么速度呢(我使用n = 500000来获得更快的时间结果):
%timeit initial(n, a, b, c, eps, sigma1, r1)
1 loop, best of 3: 7.27 s per loop
%timeit normal(n, a, b, c, eps, sigma2, r2)
1 loop, best of 3: 4.49 s per loop
%timeit function(n, a, b, c, eps, sigma3, r3)
100 loops, best of 3: 17.7 ms per loop
我知道你不想要cython所以numba可能也是不可能的,但加速是惊人的(快410倍!)
答案 1 :(得分:1)
这里我已经考虑了一些术语,所以它应该运行得更快
sigma2 = np.ones(n)*a
eps2 = eps**2
eps2[0] = 0
abc = b*eps2+c
for i in range(1,n):
#sigma2[i] = a + b * sigma2[i-1]*eps2[i-1] + c * sigma2[i-1]
sigma2[i] = a + abc[i-1]*sigma2[i-1]
print np.sqrt(sigma2)
print np.allclose(sigma, np.sqrt(sigma2))
print np.sqrt(sigma2*eps2) # r
我试图将a+
分解出来,但还没有得到匹配的结果。如果我能做到这一点,我认为可以用
np.cumprod(abc)