代码优化 Python

3
我编写了下面的函数,用于从3轴加速度计信号(X、Y、Z)估计方向。
X.shape
Out[4]: (180000L,)
Y.shape
Out[4]: (180000L,)
Z.shape
Out[4]: (180000L,)

def estimate_orientation(self,X,Y,Z):

    sigIn=np.array([X,Y,Z]).T
    N=len(sigIn)
    sigOut=np.empty(shape=(N,3))
    sigOut[sigOut==0]=None
    i=0
    while i<N:
        sigOut[i,:] = np.arccos(sigIn[i,:]/np.linalg.norm(sigIn[i,:]))*180/math.pi
        i=i+1

    return sigOut

使用 180000 个样本的信号执行此函数需要相当长的时间(约为2.2秒)... 我知道它不是以“Pythonic方式”编写的... 你能帮我优化执行时间吗?

谢谢!


180000,3 我已经编辑了问题 - gabboshow
1个回答

6

开始方法

一种遵循使用broadcasting的方法是这样的 -

np.arccos(sigIn/np.linalg.norm(sigIn,axis=1,keepdims=1))*180/np.pi

进一步优化 - I

我们可以使用np.einsum来代替np.linalg.norm部分。因此:

np.linalg.norm(sigIn,axis=1,keepdims=1)

可以被替换为:

np.sqrt(np.einsum('ij,ij->i',sigIn,sigIn))[:,None]

进一步优化 - II
可以通过使用 numexpr 模块进一步提高性能,该模块在处理大型数组和涉及三角函数的操作时表现非常出色。在我们的情况下,我们需要使用arccos函数。因此,我们将使用前面优化部分中使用的 einsum 部分,然后在其上使用 numexpr 中的 arccos 函数。
因此,实现将类似于以下内容:
import numexpr as ne

pi_val = np.pi
s = np.sqrt(np.einsum('ij,ij->i',signIn,signIn))[:,None]
out = ne.evaluate('arccos(signIn/s)*180/pi_val')

运行时测试

有以下几种方法 -

def original_app(sigIn):
    N=len(sigIn)
    sigOut=np.empty(shape=(N,3))
    sigOut[sigOut==0]=None
    i=0
    while i<N:
        sigOut[i,:] = np.arccos(sigIn[i,:]/np.linalg.norm(sigIn[i,:]))*180/math.pi
        i=i+1
    return sigOut

def broadcasting_app(signIn):
    s = np.linalg.norm(signIn,axis=1,keepdims=1)
    return np.arccos(signIn/s)*180/np.pi

def einsum_app(signIn):
    s = np.sqrt(np.einsum('ij,ij->i',signIn,signIn))[:,None]
    return np.arccos(signIn/s)*180/np.pi

def numexpr_app(signIn):
    pi_val = np.pi
    s = np.sqrt(np.einsum('ij,ij->i',signIn,signIn))[:,None]
    return ne.evaluate('arccos(signIn/s)*180/pi_val')

时间 -

In [115]: a = np.random.rand(180000,3)

In [116]: %timeit original_app(a)
     ...: %timeit broadcasting_app(a)
     ...: %timeit einsum_app(a)
     ...: %timeit numexpr_app(a)
     ...: 
1 loops, best of 3: 1.38 s per loop
100 loops, best of 3: 15.4 ms per loop
100 loops, best of 3: 13.3 ms per loop
100 loops, best of 3: 4.85 ms per loop

In [117]: 1380/4.85 # Speedup number
Out[117]: 284.5360824742268

280x 的加速!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接