Generalise Slicing Operation in a Numpy Array

Generalise slicing operation in a NumPy array

Here's the extension to handle generic ndarrays -

def indices_merged_arr_generic(arr, arr_pos="last"):
n = arr.ndim
grid = np.ogrid[tuple(map(slice, arr.shape))]
out = np.empty(arr.shape + (n+1,), dtype=np.result_type(arr.dtype, int))

if arr_pos=="first":
offset = 1
elif arr_pos=="last":
offset = 0
else:
raise Exception("Invalid arr_pos")

for i in range(n):
out[...,i+offset] = grid[i]
out[...,-1+offset] = arr
out.shape = (-1,n+1)

return out

Sample runs

2D case :

In [252]: arr
Out[252]:
array([[37, 32, 73],
[95, 80, 97]])

In [253]: indices_merged_arr_generic(arr)
Out[253]:
array([[ 0, 0, 37],
[ 0, 1, 32],
[ 0, 2, 73],
[ 1, 0, 95],
[ 1, 1, 80],
[ 1, 2, 97]])

In [254]: indices_merged_arr_generic(arr, arr_pos='first')
Out[254]:
array([[37, 0, 0],
[32, 0, 1],
[73, 0, 2],
[95, 1, 0],
[80, 1, 1],
[97, 1, 2]])

3D case :

In [226]: arr
Out[226]:
array([[[35, 45, 33],
[48, 38, 20],
[69, 31, 90]],

[[73, 65, 73],
[27, 51, 45],
[89, 50, 74]]])

In [227]: indices_merged_arr_generic(arr)
Out[227]:
array([[ 0, 0, 0, 35],
[ 0, 0, 1, 45],
[ 0, 0, 2, 33],
[ 0, 1, 0, 48],
[ 0, 1, 1, 38],
[ 0, 1, 2, 20],
[ 0, 2, 0, 69],
[ 0, 2, 1, 31],
[ 0, 2, 2, 90],
[ 1, 0, 0, 73],
[ 1, 0, 1, 65],
[ 1, 0, 2, 73],
[ 1, 1, 0, 27],
[ 1, 1, 1, 51],
[ 1, 1, 2, 45],
[ 1, 2, 0, 89],
[ 1, 2, 1, 50],
[ 1, 2, 2, 74]])

Numpy array slicing to return sliced array and corresponding array indices

You can use numpy's slice np.s_[] with a tiny bit of gymnastics to get the indices you are looking for:

slc = np.s_[:, ::3]

shape = original.shape
ix = np.unravel_index(np.arange(np.prod(shape)).reshape(shape)[slc], shape)

>>> ix
(array([[0, 0],
[1, 1]]),
array([[0, 3],
[0, 3]]))

>>> original[ix]
array([[5, 3],
[8, 6]])

>>> original[slc]
array([[5, 3],
[8, 6]])

Note that this works with slices that have some reverse direction:

slc = np.s_[:, ::-2]

# ... (as above)

>>> ix
(array([[0, 0, 0],
[1, 1, 1]]),
array([[4, 2, 0],
[4, 2, 0]]))

>>> np.array_equal(original[ix], original[slc])
True

Using a string to define Numpy array slice

you can do something like:

var1="img"
prescan_area_def = "[:, :20]"

and to use eval

prescan_area=eval(var1+prescan_area_def)

Selecting multiple slices from a numpy array at once

You can use the indexes to select the rows you want into the appropriate shape.
For example:

 data = np.random.normal(size=(100,2,2,2))

# Creating an array of row-indexes
indexes = np.array([np.arange(0,5), np.arange(1,6), np.arange(2,7)])
# data[indexes] will return an element of shape (3,5,2,2,2). Converting
# to list happens along axis 0
data_extractions = list(data[indexes])

np.all(data_extractions[1] == data[1:6])
True

The final comparison is against the original data.

Indexing a numpy array using a numpy array of slices

Your slices produce 2x6 and 2x3 arrays.

In [36]: subslice=slices[:2,1:3]
In [37]: subslice[0,0]
Out[37]: array([slice(0, 2, None), slice(6, 12, None)], dtype=object)

In [38]: ar[tuple(subslice[0,0])]
Out[38]:
array([[ 6, 7, 8, 9, 10, 11],
[21, 22, 23, 24, 25, 26]])

My numpy version expects me to turn the subslice into a tuple. This is the same as

ar[slice(0,2), slice(6,12)]
ar[:2, 6:12]

That's just the basic syntax of indexing and slicing. ar is 2d, so ar[(i,j)] requires a 2 element tuple - of slices, lists, arrays, or integers. It won't work with an array of slice objects.

How ever it is possible to concatenate the results into a larger array. That can be done after indexing or the slices can be converted into indexing lists.

np.bmat for example concatenates together a 2d arangement of arrays:

In [42]: np.bmat([[ar[tuple(subslice[0,0])], ar[tuple(subslice[0,1])]], 
[ar[tuple(subslice[1,0])],ar[tuple(subslice[1,1])]]])
Out[42]:
matrix([[ 6, 7, 8, 9, 10, 11, 12, 13, 14],
[21, 22, 23, 24, 25, 26, 27, 28, 29],
[36, 37, 38, 39, 40, 41, 42, 43, 44],
[51, 52, 53, 54, 55, 56, 57, 58, 59]])

You could generalize this. It just uses hstack and vstack on the nested lists. The result is np.matrix but can be converted back to array.

The other approach is to use tools like np.arange, np.r_, np.xi_ to create index arrays. It'll take some playing around to generate an example.

To combine the [0,0] and [0,1] subslices:

In [64]: j = np.r_[subslice[0,0,1],subslice[0,1,1]]
In [65]: i = np.r_[subslice[0,0,0]]

In [66]: i,j
Out[66]: (array([0, 1]), array([ 6, 7, 8, 9, 10, 11, 12, 13, 14]))
In [68]: ix = np.ix_(i,j)
In [69]: ix
Out[69]:
(array([[0],
[1]]), array([[ 6, 7, 8, 9, 10, 11, 12, 13, 14]]))

In [70]: ar[ix]
Out[70]:
array([[ 6, 7, 8, 9, 10, 11, 12, 13, 14],
[21, 22, 23, 24, 25, 26, 27, 28, 29]])

Or with i = np.r_[subslice[0,0,0], subslice[1,0,0]], ar[np.ix_(i,j)] produces the 4x9 array.

Slice 1D Array in Numpy without loop

If you're just after the first two characters from each hex value, one option is to recast your array to a dtype of '|S2':

>>> x.astype('|S2')
array(['83', '83', '83', '84', '84', '84', '83', '85', '85', '83'],
dtype='|S2')

This idea can be generalised to return the first n characters from each string.

Arbitrary slicing of string arrays is much more difficult to do in NumPy. Answers on this Stack Overflow page explain why it isn't the best tool for strings but show what can be possible.

Alternatively, the Pandas library facilitates fast vectorized operations (being built on top of NumPy). It has a number of very useful string operations which makes slicing a whole lot simpler than plain NumPy:

>>> import pandas as pd
>>> s = pd.Series(x)
>>> s.str.slice(2, 9)
0 8383747
1 83835F6
2 8383848
3 84835C5
4 8484787
5 8484505
6 8383757
7 8484555
8 8584535
9 8383848
dtype: object

New array from existing one, 2 column begin indexes of line/colum from the existing, third being values

You can create a meshgrid of 2D coordinates for the rows and columns, then unroll these into 1D arrays. You can then concatenate these two arrays as well as the unrolled version of t into one final matrix:

import numpy as np
(Y, X) = np.meshgrid(np.arange(t.shape[1]), np.arange(t.shape[0]))
db = np.column_stack((X.ravel(), Y.ravel(), t.ravel()))

Example run

In [9]: import numpy as np

In [10]: t = np.array([[0, 2.5],
...: [0, 0]])

In [11]: (Y, X) = np.meshgrid(np.arange(t.shape[1]), np.arange(t.shape[0]))

In [12]: db = np.column_stack((X.ravel(), Y.ravel(), t.ravel()))

In [13]: db
Out[13]:
array([[ 0. , 0. , 0. ],
[ 0. , 1. , 2.5],
[ 1. , 0. , 0. ],
[ 1. , 1. , 0. ]])

Most concise way to get complementary slice in numpy

Here's one concise way with np.r_ to generate those indices and then indexing into the input array -

A[np.r_[:start,stop:len(A)]]


Related Topics



Leave a reply



Submit