执行双重求和的最佳方式

时间:2015-02-21 00:32:15

标签: python performance math sum

例如,如下所示,假设执行了数十万次操作,我怎样才能最佳地计算Gxx?如果我只是嵌套for循环来执行求和,则需要很长时间。有没有办法使用sum函数或其他东西来提高这个过程的效率?: enter image description here

作为参考,我当前的伪代码执行此操作:

rrange=range(r-(rows-1)/2,r+(rows-1)/2)
crange=range(c-(cols-1)/2,c+(cols-1)/2)
Gxx=0
for rval,cval in product(rrange,crange):
        #sum( for x in range())
        Gxx+=(someval(rval,cval)-someval2)^2

1 个答案:

答案 0 :(得分:1)

为计算 G xx (r,c)元素的单个元素,您无法优化任何内容。这是合乎逻辑的:毕竟你对 x 的结构一无所知,所以你必须阅读所有 x j,i 范围内的元素。

但是,如果您需要计算整个矩阵,情况会发生变化。在这种情况下,您可以重复计算前一个元素的工作

首先是一些基础数学。由于 x-bar(r,c)并不依赖于 j i ,因此它在过程中是不变的。现在我们知道了:

(a-b)^2 = a^2+b^2-2*a*b

使用 b ,如果将其替换为 x-bar 常量。因此,如果您将此应用于sommation,您可以声明:

---                ---
\                  \
/     (x_ji-b)^2 = /   x_ji^2-2*b*x_ji+b^2   = S-2*s*b-D*b^2
---                ---
i,j                i,j

使用S x - 元素的正方形 s 的总和 x < / em> elements。

现在,如果您查看矩阵,第一次迭代,您将使用矩阵的某个域:

x  x  x  x  x  x  x  x  x
  /-------\
x |x  x  x| x  x  x  x  x
  |       |
x |x  x  x| x  x  x  x  x
  |       |
x |x  x  x| x  x  x  x  x
  \-------/
x  x  x  x  x  x  x  x  x

next 迭代,你只需要进一步移动范围一个元素:

x  x  x  x  x  x  x  x  x
     /-------\
x  x |x^ x^ x| x  x  x  x
     |       |
x  x |x^ x^ x| x  x  x  x
     |       |
x  x |x^ x^ x| x  x  x  x
     \-------/
x  x  x  x  x  x  x  x  x

x表示的^换言之重用。所以可以做的是使用某种滑动窗口。

第一次这样计算出第一个元素的总和和平方和(存储它们)。每次移动&#34;光标&#34;再次减去不再在范围内的行列,并添加范围中显示的列。因此,基本算法是:

for r in range (rmin,rmax) :
    sum = 0
    sumsq = 0
    jmin = r-(rows-1)/2
    jmax = r+(rows-1)/2

    #calculate sum and sum of square of the first
    imin = cmin-(cols-1)/2
    imax = cmin+(cols-1)/2
    for j,i in product(range(jmin,jmax),range(imin,imax)) :
        xji = x(j,i) #cache xji
        sum += xji
        sumsq += xji * xji
    d = (jmax-jmin)*(imax-imin)
    #now we can calculate the first element of the row
    xb = xbar(r,cmin)
    Gxx(r,cmin) = sumsq-2*sum*xb+d*xb*xb

    #now iterate over all elements (except the first)
    for c in range(cmin+1,cmax) :
        isub = c-1-(cols-1)/2 #column to remove, (previous column = -1)
        iadd = c+(cols-1)/2 #column to add
        for j in range(jmin,jmax) :
            xji = x(j,isub)
            sum -= xji
            sumsq -= xji*xji
            xji = x(j,iadd)
            sum += xji
            sumsq += xji*xji
        #Now the sums and the sum of squares are updated
        xb = xbar(r,c)
        Gxx(r,c) = sumsq-2*sum*xb+d*xb*xb

我认为应该有一些工作来调整算法,但它应该是可行的。此外,请先检查一个小实例是否正常。可能存在小的舍入误差。

如果colsrows很小,这不会有太大差别,但如果这些情况很大,则可能会带来巨大的推动。