Python中的串行矢量减法或"减法卷积"?

时间:2016-06-01 15:22:57

标签: python python-3.x numpy convolution least-squares

首先,我想对问题标题不清楚表示道歉:原因是我无法确定工作中的数学过程。

简而言之,情况如下:

  1. 我有两个不同长度的矢量f1和f2。
  2. 我想计算f1和f2之间的最小平方距离,元素。
  3. 以下是我的工作方式,

    import numpy as np
    
    def distLstSq(f1,f2):
        "Return the least square distance between f1 and f2 per unit element"
        return np.sum(np.square(np.subtract(f1,f2)))/len(f1)
    
    f1 = np.arange(100)
    f2 = np.random.random_integers(1,100,5)
    
    nBuf = len(f2)
    dist = np.empty(len(f1)-nBuf)
    for i in range(len(f1)-nBuf):
        temp = f1[i:i+nBuf]
        dist[i] = distLstSq(temp,f2)
    

    然而,由于大向量f1(从4MB的文件生成),我想知道是否没有更优雅的pythonic解决方案,使用更少的CPU资源,在更短的时间内。可能是一种减法卷积"其中f2在元素方向上滑过f1,每一步都有减法运算。

    非常感谢您的投入!

    Bertrand

1 个答案:

答案 0 :(得分:2)

首先,我想指出dist中的字词数不是len(f1)-nBuf而是len(f1)-nBuf+1。这就是短矢量与较长矢量完全重叠的方式。

忽略len(f1)的除法,它只是按常量缩放,你为f2的每个切片计算以下内容:

summation

所以我认为你可以通过一些预先计算来减少操作次数。我们还可以使用np.convolve来查找交叉术语。

f1_squared = f1**2
f2_squared_sum = np.sum(f2**2)
nBuf = len(f2)
cross_terms = -2*np.convolve(f1, f2[::-1], "valid")
# reverse f2 to get what we want. 
# "valid" returns  where vectors completely overlap
squared_distance = [f2_squared_sum + np.sum(f1_squared[i:i+nBuf]) + cross_terms[i] 
                    for i in xrange(len(cross_terms))]
mean_squared_distance = np.array(squared_distance)/nBuf

您的版本:

nBuf = len(f2)
dist = np.empty(len(f1)-nBuf+1)
for i in xrange(len(f1)-nBuf+1):
    temp = f1[i:i+nBuf]
    dist[i] = distLstSq(temp,f2)

基于timeit.timeit,我的版本速度提高了30-50%。

通过优化np.sum(f1_squared[i:i+nBuf])可以进一步提高性能,因为这涉及重复操作。应该有一些分而治之的方法来做总和。

另外我认为scipy.signal.fftconvolve可能比np.convolve更快,但这取决于较短矢量的长度(see here)