我有一个函数需要至少评估 1e6 次。它只需要两个数组作为输入。
import numpy as np
np.random.seed(1)
res = np.random.rand(0,1,1000)
f1 = lambda r, sig: -0.5*(np.sum(2*np.log(sig) + np.log(2*np.pi) + (r/sig)**2))
目前,
%timeit f1(res,np.sqrt(res))
时钟频率为 26 usc。有什么方法可以让我获得更快的评估调用/执行时间?
任何手段都可以;例如不使用 lambda 函数,使用 native 数学而不是 numpy,或任何涉及使用 Python 中实现的更快数学运算来操作方程的技巧。
编辑:
我犯了一个愚蠢的错误,生成了一个空的 res
数组。所以应该是这样
res=np.random.rand(1000)
此外,第二个数组np.sqrt(res)
实际上独立于res
,并且通常由比res
小得多的值组成,但我使用 sqrt(res)
只是为了说明。
所以重写代码更清晰
import numpy as np
np.random.seed(1)
res1 = np.random.rand(1000)
res2 = np.sqrt(res) #not true in general but res2<res1
f1 = lambda r, sig: -0.5*(np.sum(2*np.log(sig) + np.log(2*np.pi) + (r/sig)**2))
现在 %f1(res1,res2)
在我的机器上以 60 usec 计时。
最佳答案
供引用,f1
您定义的方式给了我:
10000 loops, best of 3: 20.9 µs per loop
一个简单的优化,以避免每次都计算np.log(2*np.pi)
:
log2pi = np.log(2*np.pi)
f2 = lambda r, sig: -0.5*(np.sum(2*np.log(sig) + log2pi + (r/sig)**2))
这将我的 timeit
输出减少了大约 15%:
100000 loops, best of 3: 17.8 µs per loop
此外,计算 x*x
通常比计算 x**2
更快。通过这种方法,您也可以避免 2*
操作。
def f3(r, sig):
sig2 = sig * sig
return -0.5*(np.sum(np.log(sig2) + log2pi + (r*r/sig2)))
100000 loops, best of 3: 15 µs per loop
此外,根据您使用参数 res, np.sqrt(res)
调用此函数的频率,您绝对可以考虑将其简化为:
f4 = lambda a: -0.5*np.sum(np.log(a) + log2pi + a)
您可以检查 f4(res) == f1(res, np.sqrt(res))
并且它的运行速度也显着加快(大约 44%)。
100000 loops, best of 3: 11.7 µs per loop
关于python - 更快地调用函数求值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47366872/