Numpy - 考虑抵消分割矩阵

and*_*and 5 numpy python-2.7

给定一个m x n矩阵我想把它分成a x a任意偏移的矩形(a = 3或a = 4)矩阵(最小偏移= 1,最大偏移=块大小),就像Mathematica的Partition函数一样:

例如,给定的4×4矩阵A

1  2  3  4 
5  6  7  8
9  10 11 12
13 14 15 16
Run Code Online (Sandbox Code Playgroud)

如果我给3 x 3块并且offset = 1,我想获得4个矩阵:

1  2  3 
5  6  7 
9  10 11

2  3  4 
6  7  8
10 11 12

5  6  7 
9  10 11
13 14 15

6  7  8
10 11 12
14 15 16
Run Code Online (Sandbox Code Playgroud)

如果矩阵AA = np.arange(1, 37).reshape((6,6)),我使用3 x 3块,偏移= 3,我想要输出块:

1  2  3
7  8  9
3 14 15

 4  5  6
10 11 12
16 17 18

19 20 21
25 26 27
31 32 33

22 23 24
28 29 30
34 35 36
Run Code Online (Sandbox Code Playgroud)

我很好,矩阵A是一个列表列表,我认为我不需要NumPy的功能.令我感到惊讶的是,既array_split没有numpy.split开箱即用也没有提供这种偏移选项,是否可以通过切片在纯Python中编写代码更直接,还是应该研究NumPy的步伐?我希望代码高度清晰.

hpa*_*ulj 3

正如你所暗示的,有一种方法可以做到这一点strides

In [900]: M = np.lib.stride_tricks.as_strided(A, shape=(2,2,3,3), strides=(16,4,16,4))
In [901]: M
Out[901]: 
array([[[[ 1,  2,  3],
         [ 5,  6,  7],
         [ 9, 10, 11]],

        [[ 2,  3,  4],
         [ 6,  7,  8],
         [10, 11, 12]]],


       [[[ 5,  6,  7],
         [ 9, 10, 11],
         [13, 14, 15]],

        [[ 6,  7,  8],
         [10, 11, 12],
         [14, 15, 16]]]])
In [902]: M.reshape(4,3,3)  # to get it in form you list
Out[902]: 
array([[[ 1,  2,  3],
        [ 5,  6,  7],
        [ 9, 10, 11]],

       [[ 2,  3,  4],
        [ 6,  7,  8],
        [10, 11, 12]],

       [[ 5,  6,  7],
        [ 9, 10, 11],
        [13, 14, 15]],

       [[ 6,  7,  8],
        [10, 11, 12],
        [14, 15, 16]]])
Run Code Online (Sandbox Code Playgroud)

跨步的一个问题是它是高级的,并且很难向没有太多麻木经验的人解释。我没有经过太多的尝试和错误就想出了这个表格,但我已经在这里闲逛太久了。:) )。

但这个迭代解决方案更容易解释:

In [909]: alist=[]
In [910]: for i in range(2):
     ...:     for j in range(2):
     ...:         alist.append(A[np.ix_(range(i,i+3),range(j,j+3))])
     ...:         
In [911]: alist
Out[911]: 
[array([[ 1,  2,  3],
        [ 5,  6,  7],
        [ 9, 10, 11]]), 
 array([[ 2,  3,  4],
        [ 6,  7,  8],
        [10, 11, 12]]), 
 array([[ 5,  6,  7],
        [ 9, 10, 11],
        [13, 14, 15]]), 
 array([[ 6,  7,  8],
        [10, 11, 12],
        [14, 15, 16]])]
Run Code Online (Sandbox Code Playgroud)

可以将其转换为数组np.array(alist)。如果更清楚的话,使用这个并没有什么问题。

关于该方法需要记住的一件事as_strided是,它是一种视图,对 的更改M可能会更改A,并且 中的一个位置的更改M可能会修改 中的多个位置M。但这种重塑M可能会将其变成副本。因此,总的来说,从 读取值并将其用于和 等M计算会更安全。现场变化可能是不可预测的。summean

迭代解决方案会在各处生成副本。

迭代解决方案用np.ogrid而不是np.ix_(否则相同的想法):

np.array([A[np.ogrid[i:i+3, j:j+3]] for i in range(2) for j in range(2)])
Run Code Online (Sandbox Code Playgroud)

和都是构建用于索引块的向量对的简单方法ix_ogrid

In [970]: np.ogrid[0:3, 0:3]
Out[970]: 
[array([[0],
        [1],
        [2]]), array([[0, 1, 2]])]
Run Code Online (Sandbox Code Playgroud)

相同的事情,但是slice对象:

np.array([A[slice(i,i+3), slice(j,j+3)] for i in range(2) for j in range(2)])
Run Code Online (Sandbox Code Playgroud)

其列表版本将具有view与解决方案类似的行为as_strided(列表的元素是视图)。

对于具有非重叠块的 6x6,请尝试:

In [1016]: np.array([A[slice(i,i+3), slice(j,j+3)] for i in range(0,6,3) for j i
      ...: n range(0,6,3)])
Out[1016]: 
array([[[ 1,  2,  3],
        [ 7,  8,  9],
        [13, 14, 15]],

       [[ 4,  5,  6],
        [10, 11, 12],
        [16, 17, 18]],

       [[19, 20, 21],
        [25, 26, 27],
        [31, 32, 33]],

       [[22, 23, 24],
        [28, 29, 30],
        [34, 35, 36]]])
Run Code Online (Sandbox Code Playgroud)

假设您想要连续的块,内部切片/范围不会改变,只是外部i和外部的步进j

In [1017]: np.arange(0,6,3)
Out[1017]: array([0, 3])
Run Code Online (Sandbox Code Playgroud)