1
votes

I'm trying, unsuccessfully, to combine numpy array slicing and advanced indexing. For example I have a numpy array filled with 1/0's

r = np.array([0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0])

I find the indexes of non zero elements :

(nz,) = np.nonzero(r)

I would then like to use the array of non zero indexes to operate on my array r. For each index in r I would like to colour a range (in the below 5) of values forward in r. Something like -

r[nz,:nz:nz+5] = 255

which gives result :

array([ 0, 0, 255, 255, 0, 255, 0, 0, 255, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0])

I would however have expected the following :

array([ 0, 0, 255, 255, 255 , 255, 255, 255 , 255, 255 , 255, 255, 255, 255, 255, 0, 0, 0, 0, 0])

given my indexing [nz,:nz:nz+5] = 255. Which I believe to mean from current index nz to nz+5 set value to 255.

My objective is to avoid having to for-loop iterate over the array for efficiency reasons. I'm relatively new to python and numpy so all suggestions are welcome.

2
Can you please edit your question with a sample input and expected output? - Korem
This is an index error, just was a bug in some older numpy versions that it is allowed at all. You have two indices for one dimension. - seberg

2 Answers

0
votes

How about creating a matrix of the slices:

>>> import numpy as np
>>> r = np.array([0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0])
>>> nz = np.nonzero(r)
>>> slices = np.vstack(np.arange(x, x + 5) for x in nz[0])
>>> slices
array([[ 2,  3,  4,  5,  6],
       [ 3,  4,  5,  6,  7],
       [ 5,  6,  7,  8,  9],
       [ 8,  9, 10, 11, 12],
       [10, 11, 12, 13, 14]], dtype=int64)
>>> r[slices]
array([[1, 1, 0, 1, 0],
       [1, 0, 1, 0, 0],
       [1, 0, 0, 1, 0],
       [1, 0, 1, 0, 0],
       [1, 0, 0, 0, 0]])
>>> r[slices] = 255
>>> r
array([  0,   0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
       255, 255,   0,   0,   0,   0,   0])

Note that this code assumes that you have enough "padding" at the end. It will fail with an IndexError if it tries to index items outside r.

0
votes

Problem description resembles a typical signal convolution step. There are two modules in scipy that implement signal processing, scipy.signal and scipy.ndimage, which you may find interesting if you plan doing more of that. In this particular case, you can use generic np.convolve (notice that I added trailing 1 for illustrative purpose):

In [45]: r = np.array([0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1])

In [46]: r[np.convolve(r, np.ones(5, dtype=r.dtype))[:-4] > 0] = 255; r
Out[46]: 
array([  0,   0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
       255, 255,   0,   0,   0,   0, 255])

Here's the result of convolution operation:

In [48]: np.convolve(r, np.ones(5, dtype=r.dtype))
Out[48]: 
array([0, 0, 1, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1])

As you can see, the last 1 has produced a full sequence of 1s at the end, they should be stripped. After that, non-zero elements in convolved array will give you the required boolean mask:

In [49]: np.convolve(r, np.ones(5, dtype=r.dtype))[:-4] > 0
Out[49]: 
array([False, False,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True, False, False, False,
       False,  True], dtype=bool)