【问题标题】:Efficient way of getting average area in numpy在numpy中获取平均面积的有效方法
【发布时间】:2019-01-10 05:27:02
【问题描述】:

有没有更有效的方法来确定给定 numpy 数组中某个区域的平均值?为简单起见,假设我有一个 5x5 数组:

values = np.array([[0, 1, 2, 3, 4],
                   [1, 2, 3, 4, 5],
                   [2, 3, 4, 5, 6],
                   [3, 4, 5, 6, 7],
                   [4, 5, 6, 7, 8]])

假设数组环绕,我想获得每个坐标的平均值,具有指定的区域大小。假设某个区域的大小为2,因此将考虑距离 2 内某个点周围的任何东西。例如,要从坐标(2,2)得到区域的平均值,我们需要考虑

      2,
   2, 3, 4,
2, 3, 4, 5, 6
   4, 5, 6,
      6,

因此,平均值将为4.

对于坐标 (4, 4) 我们需要考虑:

      6,
   6, 7, 3,
6, 7, 8, 4, 5
   3, 4, 0,
      5,

因此平均值将为4.92.

目前,我有以下代码。但由于我有一个 for 循环,我觉得它可以改进。有没有办法只使用 numpy 内置函数?

有没有办法使用 np.vectorize 来收集子数组(区域),把它全部放在一个数组中,然后使用 np.einsum 什么的。

def get_average(matrix, loc, dist):
    sum = 0
    num = 0
    size, size = matrix.shape
    for y in range(-dist, dist + 1):
        for x in range(-dist + abs(y), dist - abs(y) + 1):
            y_ = (y + loc.y) % size
            x_ = (x + loc.x) % size

            sum += matrix[y_, x_]
            num += 1

    return sum/num

class Coord():
    def __init__(self, x, y):
        self.x = x
        self.y = y

values = np.array([[0, 1, 2, 3, 4],
                     [1, 2, 3, 4, 5],
                     [2, 3, 4, 5, 6],
                     [3, 4, 5, 6, 7],
                     [4, 5, 6, 7, 8]])

height, width = values.shape

averages = np.zeros((height, width), dtype=np.float16)

for r in range(height):
    for c in range(width):
        loc = Coord(c, r)
        averages[r][c] = get_average(values, loc, 2)

print(averages)

输出:

[[ 3.07617188  2.92382812  3.5390625   4.15234375  4.        ]
 [ 2.92382812  2.76953125  3.38476562  4.          3.84570312]
 [ 3.5390625   3.38476562  4.          4.6171875   4.4609375 ]
 [ 4.15234375  4.          4.6171875   5.23046875  5.078125  ]
 [ 4.          3.84570312  4.4609375   5.078125    4.921875  ]]

【问题讨论】:

    标签: python numpy vectorization


    【解决方案1】:

    这个解决方案比你的效率低​​(慢),但只是使用numpy.ma 模块的一个例子。

    所需的库:

    import numpy as np
    import numpy.ma as ma
    

    定义完成工作的方法:

    # build the shape of the area as a rhomboid
    def rhomboid2(dim):
        size = 2*dim + 1
        matrix = np.ones((size,size))
        for y in range(-dim, dim + 1):
          for x in range(-dim + abs(y), dim - abs(y) + 1):
            matrix[(y + dim) % size, (x + dim) % size] = 0
        return matrix
    
    # build a mask using the area shaped
    def mask(matrix_shape, rhom_dim):
      mask = np.zeros(matrix_shape)
      bound = 2*rhom_dim+1
      rhom = rhomboid2(rhom_dim)
      mask[0:bound, 0:bound] = rhom
      # roll to set the position of the rhomboid to 0,0
      mask = np.roll(mask,-rhom_dim, axis = 0)
      mask = np.roll(mask,-rhom_dim, axis = 1)
      return mask
    

    然后,迭代构建结果:

    mask_ = mask((5,5), 2) # call the mask sized as values array with a rhomboid area of size 2
    averages = np.zeros_like(values, dtype=np.float16) # initialize the recipient
    # iterate over the mask to calculate the average
    for y in range(len(mask_)):
      for x in range(len(mask_)):
        masked = ma.array(values, mask = mask_)
        averages[y,x] = np.mean(masked)
        mask_ = np.roll(mask_, 1, axis = 1)
      mask_ = np.roll(mask_, 1, axis = 0)
    

    返回

    # [[3.076 2.924 3.54  4.152 4.   ]
    #  [2.924 2.77  3.385 4.    3.846]
    #  [3.54  3.385 4.    4.617 4.46 ]
    #  [4.152 4.    4.617 5.23  5.08 ]
    #  [4.    3.846 4.46  5.08  4.92 ]]
    

    【讨论】:

    • 我明白了。感谢您向我展示了另一种选择。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多