Numpy: building multiple fragments into a new array

I have a 2-dimensional array from which I need to extract sections (slices) into a new array:

original= numpy.ndarray( shape=(4,4) ) slices= numpy.ndarray( shape=(0,2) ) for x in range(3): slice= original[x:x+2,x:x+2] slices=numpy.append(slices, slice,axis=0) 

Is there a more efficient way to do this (get rid of python for a loop)?

---- ---- EDIT

To clarify, I ask how to copy randomly (but similarly) 2D fragments from arbitrary 2D indexes of a 2D array to another, vertically stacked - not especially diagonally or 2x2 in size.

+4
source share
2 answers

There is a great trick with stride_tricks , you can find framing functions with different generalities on SO and others (currently not in numpy), here is a version adapted to what you got:

 def rolling_window(arr, window): """Very basic multi dimensional rolling window. window should be the shape of of the desired subarrays. Window is either a scalar or a tuple of same size as `arr.shape`. """ shape = np.array(arr.shape*2) strides = np.array(arr.strides*2) window = np.asarray(window) shape[arr.ndim:] = window # new dimensions size shape[:arr.ndim] -= window - 1 if np.any(shape < 1): raise ValueError('window size is too large') return np.lib.stride_tricks.as_strided(arr, shape=shape, strides=strides) # Now: view = rolling_window(arr, 2) view[0,0] # first slice in your loop 

Note that view contains the same data as the original array! This may lead to unexpected results. But it seems to you that you only need a diagonal, you can do this with tricks with steps to make sure that you do not copy the data if you want (in future versions a view with diagonal , old ones are always a copy):

 diagonal = np.diagonal(view, axis1=0, axis2=1) # unfortunatly now the first slice is diagonal[...,0], so just roll it to the start: diagonal = np.rollaxis(diagonal, -1) 

Now diagonal is the array that you created in the for loop (in new versions add .copy() if you don't want a view).

Edit: since the slices array is 2D, not 3D, because you are adding, there have been no changes:

 slices = diagonal.reshape(-1,2) 

It may not be so fast if you have such small arrays, but its constant (waiting to copy data in a diagonal call) with the size of the array.

+3
source

Here is your solution:

 v = np.arange(0,original.shape[0],0.5).astype(int) result = np.c_[ original[v[1:-1],v[:-2]] , original[v[1:-1],v[2:]] ] 

works for any size of square input matrix ("original", as you called it).

The idea is to create an “auxiliary array” v that is simple [0,0,1,1,2,2,3,3, ...] and then use the observation that the required indexes are always simple slices of v.

Enjoy it!

+1
source

Source: https://habr.com/ru/post/1439593/


All Articles