Python 使用numpy优化此循环

Python 使用numpy优化此循环,python,numpy,cython,numerical-methods,Python,Numpy,Cython,Numerical Methods,通过以下方式递归生成500万点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)

通过以下方式递归生成500万点
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
但是在不得不在这种情况下使用Cython之前,我想知道:会有一个简单的Numpy/Python方法,我不知道它会优化这么多吗?这里我已经考虑了一些术语,所以它应该运行得更快

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)

这里我已经考虑了一些术语,所以它应该运行得更快

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)

只需将其改为
math.sqrt
,而不是
np.sqrt
,这里的加速率约为40%

因为我是一个狂热的麻木迷,我试过麻木版和你的(
initial
)和数学版(
normal

然后验证结果是否相同:

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结果):


我知道你不想要cython,所以numba可能也是不可能的,但是它的加速比太惊人了(快410倍!)

只需将它改为
math.sqrt
而不是
np.sqrt
就可以给你40%的加速比

因为我是一个狂热的麻木迷,我试过麻木版和你的(
initial
)和数学版(
normal

然后验证结果是否相同:

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结果):


我知道你不想要cython,所以numba可能也是不可能的,但是当
ith
值取决于
ith-1
时,它的加速速度是惊人的(快410倍)

我们尝试使用
cumsum
cumprod
和其他
ufunc.accumulate
函数。你的表情能转换成那种形式吗?从这个意义上讲,这更像是一个数学系列问题,而不是一个
numpy
问题。当
ith
值取决于
ith-1
时,我们尝试使用
cumsum
cumprod
和其他
ufunc.accumulate
函数。你的表情能转换成那种形式吗?从这个意义上说,这更像是一个数学系列问题,而不是一个
numpy
问题。事实上,我没有得到与OP发布的操作相同的结果,我不知道为什么。。。某些元素的符号错误。也许我做错了什么。事实上,我在你的手术中并没有得到与OP发布的手术相同的结果,我不知道为什么。。。某些元素的符号错误。也许我做错了什么。非常感谢,我终于让
numba
工作了!不过有一点奇怪:在
@nb.njit
def函数(…)中执行
eps=np.random.normal(0.0,1.0,n)
操作:
无效:使用参数(float64,float64,int32)已知签名的函数(np.random.normal)无效:*(float64,float64)->float64*(float64,)->Nomba仍处于实验阶段。大多数(甚至全部)数学函数和numpy数学函数都在numba函数中工作,但其他所有函数。。。我不知道。我只会在实际计算中使用numba函数,并让包装器或外部函数创建结果模板或中间数组。@Basj它看起来像
numba.random.normal
只支持两个参数(log和scale):请参阅。所以你不能一次创建一个完整的数组,也许你需要创建一个
np.zeros
数组,并用单个
random
值填充它。:-)哦,这意味着使用
np.random.normal
会自动重新解释为
numba.radom.normal
?是的(当然,只在修饰函数内部)。通过调用
function\u name.inspect\u types()
非常感谢,我终于让
numba
工作了!不过有一点奇怪:在
@nb.njit
def函数(…)中执行
eps=np.random.normal(0.0,1.0,n)
操作:
无效:使用参数(float64,float64,int32)已知签名的函数(np.random.normal)无效:*(float64,float64)->float64*(float64,)->Nomba仍处于实验阶段。大多数(甚至全部)数学函数和numpy数学函数都在numba函数中工作,但其他所有函数。。。我不知道。我只会在实际计算中使用numba函数,并让包装器或外部函数创建结果模板或中间数组。@Basj它看起来像
numba.random.normal
只支持两个参数(log和scale):请参阅。所以你不能一次创建一个完整的数组,也许你需要创建一个
np.zeros
数组,并用单个
random
值填充它。:-)哦,这意味着使用
np.random.normal
会自动重新解释为
numba.radom.normal
?是的(当然,只在修饰函数内部)。通过调用
function\u name.inspect\u types()