Numpy:矢量化一个集成2D数组的函数

时间:2017-08-10 07:42:17

标签: python arrays numpy convolution integral

我需要对2D数组进行以下集成:RC 也就是说,网格中的每个点都得到值RC,它是在整个场与特定点(x,y)处的场 U 的值之间的差值的2D积分,乘以规范化内核,在1D版本中是:
enter image description here

到目前为止我所做的是对索引的低效迭代:

def normalized_bimodal_kernel_2D(x,y,a,x0=0.0,y0=0.0):
    """ Gives a kernel that is zero in x=0, and its integral from -infty to 
    +infty is 1.0. The parameter a is a length scale where the peaks of the 
    function are."""
    dist = (x-x0)**2 + (y-y0)**2
    return (dist*np.exp(-(dist/a)))/(np.pi*a**2)


def RC_2D(U,a,dx):
    nx,ny=U.shape
    x,y = np.meshgrid(np.arange(0,nx, dx),np.arange(0,ny,dx), sparse=True)
    UB = np.zeros_like(U)
    for i in xrange(0,nx):
        for j in xrange(0,ny):
            field=(U-U[i,j])*normalized_bimodal_kernel_2D(x,y,a,x0=i*dx,y0=j*dx)
            UB[i,j]=np.sum(field)*dx**2
    return UB

def centerlizing_2D(U,a,dx):
    nx,ny=U.shape
    x,y = np.meshgrid(np.arange(0,nx, dx),np.arange(0,ny,dx), sparse=True)
    UB = np.zeros((nx,ny,nx,ny))
    for i in xrange(0,nx):
        for j in xrange(0,ny):
            UB[i,j]=normalized_bimodal_kernel_2D(x,y,a,x0=i*dx,y0=j*dx)
    return UB

您可以在此处查看centeralizing功能的结果:

U=np.eye(20)
plt.imshow(centerlizing(U,10,1)[10,10])

UB 我确信我还有其他错误,所以任何反馈都会受到热烈欢迎,但我真正感兴趣的是理解如何以矢量化的方式更快地完成这项操作。

2 个答案:

答案 0 :(得分:2)

在两个嵌套循环中调用

normalized_bimodal_kernel_2D,每个循环只移动它的小步骤。这复制了许多计算。

centerlizing_2D的优化是为较大范围计算一次内核,然后定义UB以将移位视图转换为该范围。这可以使用stride_tricks,不幸的是它是相当先进的numpy。

def centerlizing_2D_opt(U,a,dx):
    nx,ny=U.shape    
    x,y = np.meshgrid(np.arange(-nx//2, nx+nx//2, dx),
                      np.arange(-nx//2, ny+ny//2, dx),  # note the increased range
                      sparse=True)
    k = normalized_bimodal_kernel_2D(x, y, a, x0=nx//2, y0=ny//2)
    sx, sy = k.strides    
    UB = as_strided(k, shape=(nx, ny, nx*2, ny*2), strides=(sy, sx, sx, sy))
    return UB[:, :, nx:0:-1, ny:0:-1]

assert np.allclose(centerlizing_2D(U,10,1), centerlizing_2D_opt(U,10,1)) # verify it's correct

是的,它的速度更快:

%timeit centerlizing_2D(U,10,1)      #   100 loops, best of 3:  9.88 ms per loop
%timeit centerlizing_2D_opt(U,10,1)  # 10000 loops, best of 3: 85.9  µs per loop

接下来,我们通过使用优化的RC_2D例程表达centerlizing_2D来优化def RC_2D_opt(U,a,dx): UB_tmp = centerlizing_2D_opt(U, a, dx) U_tmp = U[:, :, None, None] - U[None, None, :, :] UB = np.sum(U_tmp * UB_tmp, axis=(0, 1)) return UB assert np.allclose(RC_2D(U,10,1), RC_2D_opt(U,10,1))

%timeit RC_2D(U,10, 1)

#original: 100 loops, best of 3: 13.8 ms per loop #@DanielF's: 100 loops, best of 3: 6.98 ms per loop #mine: 1000 loops, best of 3: 1.83 ms per loop 的表现:

'

答案 1 :(得分:1)

为了适合您的公式,让U成为一个函数。

然后,您只需将x,y,x',y'np.ix_放在四个不同的维度中,然后将您的公式翻译。 Numpy广播将完成其余的工作。

a=20
x,y,xp,yp=np.ix_(*[np.linspace(0,1,a)]*4)

def U(x,y) : return np.float32(x == y)  # function "eye"

def f(x,y,xp,yp,a):
    r2=(x-xp)**2+(y-yp)**2
    return r2*np.exp(-r2/a)*(U(xp,yp) - U(x,y))/np.pi/a/a

#f(x,y,xp,yp,a).shape is (20, 20, 20, 20)

RC=f(x,y,xp,yp,a).sum(axis=(2,3))
#RC.shape is (20, 20)