4

For example, x = np.random.randint(low=0, high=10, shape=(6,6)) gives me a 6x6 numpy array:

array([[3, 1, 0, 1, 5, 4],
       [2, 9, 9, 4, 8, 8],
       [2, 3, 4, 3, 2, 9],
       [5, 8, 4, 5, 7, 6],
       [3, 0, 8, 1, 8, 0],
       [6, 7, 1, 9, 0, 5]])

How can I get a list of, say, all 2x3 submatrices? What about non-overlapping ones?

I could code this in myself, but I'm sure this is a common enough operation that it already exists in numpy, I just can't find it.

Divakar
  • 218,885
  • 19
  • 262
  • 358
Fequish
  • 705
  • 6
  • 17
  • 1
    There are a number of SO q and a's regarding "windows" into an array. Some use [this](http://www.johnvinyard.com/blog/?p=268) solution. – wwii Sep 21 '15 at 21:25
  • For more stride-trick implementations see the [code of scikit-image](https://github.com/scikit-image/scikit-image/blob/master/skimage/util/shape.py) and `extract_patches` from [scikit-learn](https://github.com/scikit-learn/scikit-learn/blob/master/sklearn/feature_extraction/image.py) –  Sep 24 '15 at 11:06

1 Answers1

3

Listed in this post is a generic approach to get a list of submatrices with given shape. Based on the order of submatrices being row (C-style) or column major (fortran-way), you would have two choices. Here's the implementation with np.reshape , np.transpose and np.array_split -

def split_submatrix(x,submat_shape,order='C'):
    p,q = submat_shape      # Store submatrix shape
    m,n = x.shape

    if np.any(np.mod(x.shape,np.array(submat_shape))!=0):
        raise Exception('Input array shape is not divisible by submatrix shape!')

    if order == 'C':
        x4D = x.reshape(-1,p,n/q,q).transpose(0,2,1,3).reshape(-1,p,q)
        return np.array_split(x4D,x.size/(p*q),axis=0)

    elif order == 'F':
        x2D = x.reshape(-1,n/q,q).transpose(1,0,2).reshape(-1,q)
        return np.array_split(x2D,x.size/(p*q),axis=0)

    else:
        print "Invalid output order."
        return x

Sample run with a modified sample input -

In [201]: x
Out[201]: 
array([[5, 2, 5, 6, 5, 6, 1, 5],
       [1, 1, 8, 4, 4, 5, 2, 5],
       [4, 1, 6, 5, 6, 4, 6, 1],
       [5, 3, 7, 0, 5, 8, 6, 5],
       [7, 7, 0, 6, 5, 2, 5, 4],
       [3, 4, 2, 5, 0, 7, 5, 0]])

In [202]: split_submatrix(x,(3,4))
Out[202]: 
[array([[[5, 2, 5, 6],
         [1, 1, 8, 4],
         [4, 1, 6, 5]]]), array([[[5, 6, 1, 5],
         [4, 5, 2, 5],
         [6, 4, 6, 1]]]), array([[[5, 3, 7, 0],
         [7, 7, 0, 6],
         [3, 4, 2, 5]]]), array([[[5, 8, 6, 5],
         [5, 2, 5, 4],
         [0, 7, 5, 0]]])]

In [203]: split_submatrix(x,(3,4),order='F')
Out[203]: 
[array([[5, 2, 5, 6],
        [1, 1, 8, 4],
        [4, 1, 6, 5]]), array([[5, 3, 7, 0],
        [7, 7, 0, 6],
        [3, 4, 2, 5]]), array([[5, 6, 1, 5],
        [4, 5, 2, 5],
        [6, 4, 6, 1]]), array([[5, 8, 6, 5],
        [5, 2, 5, 4],
        [0, 7, 5, 0]])]
Divakar
  • 218,885
  • 19
  • 262
  • 358