我有一些python代码,目前运行速度太慢,无法使用。完成了一些速度测试后,大部分时间似乎花在执行数学运算来计算corr(参见下面的代码)。
import numpy as np
from multiprocessing import Pool
from contextlib import closing
def calc_cc(tlag):
global phi_t, psi_t, T
tstart = tlag-T/2
x = np.arange(tstart, tstart+T, dtype=int)
#bulk of time spent running line below calculating corr
corr = np.sum(np.abs(np.cos(phi_t[tlag+x]-psi_t[x]))-np.abs(np.sin(phi_t[tlag+x]-psi_t[x])))
def main():
global phi_t, psi_t, T
phi_t = #some large numpy array
psi_t = #another numpy array
tlag = #another numpy array
with closing(Pool(processes=5)) as p:
corr = p.map(calc_cc,tlag)
p.terminate()
if __name__ == "__main__":
main()
我花了一些时间在网上寻找优化我的python代码的方法,更具体地说是数学运算,但是很多建议都是在需要时使用numpy而不是python基函数这样的包(例如使用与sum()相比,np.sum大大提高了速度。现在我已经到了使用numpy数组的点,使用numpy方法,我不知道在哪里可以找到额外的收益。我正在有效地尝试的公式解决的是:
我确信必须有更好的方法来做到这一点,因此,非常感谢任何有关更好解决方案的指导:)。
答案 0 :(得分:2)
首先,您可以通过为三角函数as @hpaulj noted计算phi_t(...)-psi_t(...)
一次来略微改进代码。但是,我看到的最大问题是您使用多处理池进行相对较轻的计算。我的猜测是,运行时的很大一部分来自使用池的开销。
如果您可以适应内存,则可以通过使用阵列广播来计算整个相关函数。通过矢量化计算,您可以最大限度地提高通过numpy获得的速度。我们的想法是使用索引phi
/ psi
数组的二维数组:列对应于原始x
索引,行对应于单个tlag
转换。您自然使用的内置numpy功能可以使用广播。
这就是我的意思,完成一些虚拟数据:
import numpy as np
def calc_cc_new(tlags):
global phi_t, psi_t, T
tstarts = tlags - T//2
xs = tstarts + np.arange(T)[:,None]
dphipsi = phi_t[tlags+xs] - psi_t[xs]
corr = np.sum(np.abs(np.cos(dphipsi)) - np.abs(np.sin(dphipsi)),axis=0)
return corr
def main_new():
global phi_t, psi_t, tlags
return calc_cc_new(tlags)
N = 10000
T = 100
phi_t = np.random.rand(N)*2*np.pi
psi_t = np.random.rand(N)*2*np.pi
tlags = np.arange(T//2,3*T)
if __name__ == "__main__":
print(main_new())
我没有检查你的多处理版本,但原版的串行版本需要8.1毫秒,而矢量化版本需要2.1毫秒(无论我是否将总和的两个术语分成单独调用{{1 }})。我检查了我的版本中返回的数组使用np.sum()
检查原始数据(由于向量化,算术运算的顺序被移动,所以我们不能期望完全协议,机器精度只有一个)。使用虚拟示例,我是否将求和维度定义为第0个或第一个并不重要,但根据您的输入数组形状,这可能会导致一些性能差异。
此外,通常不鼓励使用全局变量,并且全局命名空间查找比本地命名空间慢一点(尽管我不希望这对于你的函数是CPU很重要的事情)。无论如何,如果你放弃多处理池,你可以简单地扩展你的np.allclose
函数的定义,使它将所有输入作为参数,而不是全局变量。
最后,一旦你完成,就不要忘记calc_cc
先决条件。