首页 文章

numpy数组的固定大小子矩阵的指数

提问于
浏览
11

我正在实现一种算法,它要求我在(严格二维)numpy数组中查看非重叠的连续子矩阵 . 例如,对于12乘12

>>> a = np.random.randint(20, size=(12, 12)); a
array([[ 4,  0, 12, 14,  3,  8, 14, 12, 11, 18,  6,  6],
       [15, 13,  2, 18, 15, 15, 16,  2,  9, 16,  6,  4],
       [18, 18,  3,  8,  1, 15, 14, 13, 13, 13,  7,  0],
       [ 1,  9,  3,  6,  0,  4,  3, 15,  0,  9, 11, 12],
       [ 5, 15,  5,  6,  4,  4, 18, 13, 10, 17, 11,  8],
       [13, 17,  8, 15, 17, 12,  7,  1, 13, 15,  0, 18],
       [ 2,  1, 11, 12,  3, 16, 11,  9, 10, 15,  4, 16],
       [19, 11, 10,  7, 10, 19,  7, 13, 11,  9, 17,  8],
       [14, 14, 17,  0,  0,  0, 11,  1, 10, 14,  2,  7],
       [ 6, 15,  6,  7, 15, 19,  2,  4,  6, 16,  0,  3],
       [ 5, 10,  7,  5,  0,  8,  5,  8,  9, 14,  4,  3],
       [17,  2,  0,  3, 15, 10, 14,  1,  0,  7, 16,  2]])

看看3x3子矩阵,我希望第一个3x3子矩阵来自左上角:

>>> a[0:3, 0:3]
array([[ 4,  0, 12],
       [15, 13,  2],
       [18, 18,  3]])

接下来将由 a[0:3, 3:6] 给出,依此类推 . 它不会简单地给出存在的切片内的部分就足够了 .

我想要一种以编程方式为任意大小的矩阵和子矩阵生成这些切片索引的方法 . 我目前有这个:

size = 3
x_max = a.shape[0]
xcoords = range(0, x_max, size)
xcoords = zip(xcoords, xcoords[1:])

并且类似地生成 y_coords ,以便 itertools.product(xcoords, ycoords) 给出一系列索引 .

我的问题是:有没有更直接的方法来做到这一点,也许使用numpy.mgrid或其他一些numpy技术?

3 回答

  • 6

    获取索引

    这是获取特定 size x size 块的快速方法:

    base = np.arange(size) # Just the base set of indexes
    row = 1                # Which block you want
    col = 0                
    block = a[base[:, np.newaxis] + row * size, base + col * size]
    

    如果你想要你可以 Build 类似于你的 xcoords 的矩阵:

    y, x = np.mgrid[0:a.shape[0]/size, 0:a.shape[1]/size]
    y_coords = y[..., np.newaxis] * size + base
    x_coords = x[..., np.newaxis] * size + base
    

    然后你可以访问这样的块:

    block = a[y_coords[row, col][:, np.newaxis], x_coords[row, col]]
    

    直接获取块

    如果你只想获取块(而不是块条目的索引),我会使用np.split(两次):

    blocks = map(lambda x : np.split(x, a.shape[1]/size, 1), # Split the columns
                            np.split(a, a.shape[0]/size, 0)) # Split the rows
    

    那么你有一个 size x size 块的2D列表:

    >>> blocks[0][0]
    array([[ 4,  0, 12],
           [15, 13,  2],
           [18, 18,  3]])
    
    >>> blocks[1][0]
    array([[ 1,  9,  3],
           [ 5, 15,  5],
           [13, 17,  8]])
    

    然后,您可以将其设置为numpy数组,并使用与上面相同的索引样式:

    >>> blocks = np.array(blocks)
    >>> blocks.shape
    (4, 4, 3, 3)
    
  • 2

    你可以使用单线:

    r = 3
    c = 3
    lenr = a.shape[0]/r
    lenc = a.shape[1]/c
    np.array([a[i*r:(i+1)*r,j*c:(j+1)*c] for (i,j) in np.ndindex(lenr,lenc)]).reshape(lenr,lenc,r,c)
    
  • 5

    我正在将这个答案添加到一个旧问题,因为编辑已经提出了这个问题 . 这是计算块的另一种方法:

    size = 3
    lenr, lenc = int(a.shape[0]/size), int(a.shape[1]/size)
    
    t = a.reshape(lenr,size,lenc,size).transpose(0, 2, 1, 3)
    

    分析表明这是最快的 . 使用python 3.5进行性能分析,并将map的结果传递给array()以实现兼容性,因为在3.5 map中返回一个迭代器 .

    reshape/transpose:   643 ns per loop
    reshape/index:       45.8 µs per loop
    Map/split:           10.3 µs per loop
    

    有趣的是迭代器版本的 Map 更快 . 无论如何,使用重塑和转置是最快的 .

相关问题