确定点的给定半径内网格值平均值的最快方法

时间:2014-09-05 17:02:44

标签: python arrays numpy

我有一个numpy 2D数组值。数组中的每个元素表示网格中的网格点,每个方框的边长为13km。我需要确定网格中特定点50英里内所有点的平均值。

我当前的解决方案确定了一个边界框,然后使用它们的索引引用该框中数组中的项目,这与numpy一样慢。我正试图确定一个更快的解决方案。

目前的解决方案:

num_x = 400        #horizontal dimension of the 2D array
num_y = 300        #vertical dimension of the 2D array
num_dx = 6         #maximum number of horizontal grid points that fit within 50 miles
num_dy = 6         #same as above but for vertical (square grid)
radius_m = 80467.2 #50 miles expressed in meters
values = []        # stores the extracted values

for ix in range(-num_dx,num_dx+1):
    for jy in range(-num_dy,num_dy+1):
        # Determine distance to this point
        dist = ((ix*dx)**2+(jy*dy)**2)**0.5
        if dist <= radius_m:
            # Ensure this grid point actually exists within the grid
            if (j+jy) < num_y and (i+ix) < num_x:
                value = myarray[i+ix,j+jy]
                    if value is not masked and value >= 0:
                        values.append(float(value))

average = sum(values) / float(len(values))

由于访问myarray超过100次以提取单个元素的值,因此这很慢(大约需要1.5秒)。有没有一种矢量方法可以在这里更好地工作?我似乎无法通过掩码找到一种方法,因为条件是基于网格点相对于另一个的位置,而不是元素本身的值。

2 个答案:

答案 0 :(得分:1)

对于内部点(半径不在图像外部),您可以计算用于任何内部点的单个蒙版。从零数组开始:

mask = np.zeros((2 * num_dx + 1, 2 * num_dy + 1), dtype=np.int)

假设您的兴趣点位于该数组的中心,请将半径范围内的每个元素设置为1(此处未显示)。然后,

indices = np.argwhere(mask.ravel() == 1)

然后对于(i, j)中的任何内部元素myarray,您将得到半径范围内的值,如:

values = myarray[i-num_dx: i+num_dx+1, j-num_dy: j+num_dy+1].ravel()[indices]

对于边框附近的点,您可以制作mask的副本,并在设置indices之前将图像外的行/列设置为零。

答案 1 :(得分:1)

您的代码无法运行,似乎包含i < num_dxj < num_dy时的错误(然后它会回绕到数组的另一侧)。但是对你的变量名进行一些假设,我就是这样做的:

# First make sure we stay in the grid
i1, i2 = max(i-num_dx, 0), min(i+num_dx+1, num_x)
j1, j2 = max(j-num_dy, 0), min(j+num_dy+1, num_y)

# Get the radius in blocks, grid should be homogeneous
radius_i = radius_m / 13000.0

# Calc distances per element by broadcasting
DX = np.arange(i1, i2) - i
DY = np.arange(j1, j2)[:, None] - j
mask = DX*DX + DY*DY <= radius_i*radius_i

# Get block of interest and apply mask
values = myarray[i1:i2, j1:j2][mask]