4

What is the most efficient way to use a mask to select elements of a multidimensional numpy array, when the mask is to be applied with an offset? For example:

import numpy as np

# in real application, following line would read an image
figure = np.random.uniform(size=(4, 4))  # used as a mask
canvas = np.zeros((10, 10))

# The following doesn't do anything, because a copy is modified
canvas[np.ix_(np.arange(4) + 3, range(4))][figure > 0.5] = 1.0

print np.mean(figure > 0.5)  # should be ~ 0.5
print canvas.max()  # prints 0.0

A similar question is posted here: Setting values of Numpy array when indexing an indexed array but I'm using a mask and I'm not asking why it doesn't work.

1
  • Would you always have the open mesh arrays as arrays with sequential numbers? Commented Jan 17, 2017 at 17:02

4 Answers 4

2

The problem, it seems, is that using the arrays returned by np.ix_ as index means you are doing advanced indexing, and, as the documentation of NumPy states:

Advanced indexing always returns a copy of the data (contrast with basic slicing that returns a view).

But in this case, if the real application is similar to the code you have posted (that is, if you really just need an offset), you can get away with basic slicing:

import numpy as np

figure = np.random.uniform(size=(4, 4))
canvas = np.zeros((10, 10))

# Either of the following works fine
canvas[3:(3 + 4), :4][figure > 0.5] = 1.0
canvas[slice(3, 3 + 4), slice(4)][figure > 0.5] = 1.0

print np.mean(figure > 0.5)  # ~ 0.5
print canvas.max()  # Prints 1.0 now
Sign up to request clarification or add additional context in comments.

Comments

1

One approach would be to work with the linear indices. So, we would get the row and column indices from np.ix_, get the linear index equivalents from those. Then, use the mask to select the valid ones and finally assign new values to the data array with the valid linear indices.

Thus, the implementation would be -

# Get the open mesh arrays from np.ix_ corresponding to row, col indices
row, col = np.ix_(np.arange(4) + 3, range(4))

# Get the linear indices from those row and column index arrays 
linear_index = (row*canvas.shape[1] + col)[figure>0.5]

# Finally, assign values
np.put(canvas, linear_index, 1.0) # Or canvas.ravel()[linear_index] = 1.0

Comments

1

I generally use a helper function that creates an appropriatly shaped part (view) of the array:

arr = np.ones((10, 10)) * 10
mask = np.random.uniform(size=(4, 4))

def get_part(arr, shape, offs_x, offs_y):
    # This example just does 2D but can easily be expanded for ND-arrays
    return arr[offs_x : (offs_x + shape[0]), 
               offs_y : (offs_y + shape[1])]

get_part(arr, mask.shape, offs_x=3, offs_y=4)[mask > 0.5] = 1.0

A ND implementation would look like this:

def get_part(arr, shape, offsets):
    slices = tuple(slice(offs, offs+length) for offs, length in zip(offsets, shape))
    return arr[slices]

get_part(arr, mask.shape, (3, 4))

Comments

0
mask=figure>0.5

If ix indices are really ranges, they can be replaced with slices as @jdehesa shows:

canvas[3:3+4,:4][mask]=1

If the use of arange is just an example convenience, we could use a two stage assignment

In [277]: idx=np.ix_(np.arange(4) + 3, range(4))
In [278]: canvas = np.zeros((10, 10))
In [279]: subcanvas=np.zeros_like(figure)
In [280]: subcanvas[mask] = 1
In [281]: subcanvas
Out[281]: 
array([[ 0.,  1.,  1.,  1.],
       [ 0.,  0.,  0.,  1.],
       [ 1.,  0.,  0.,  1.],
       [ 1.,  0.,  0.,  1.]])
In [282]: canvas[idx]=subcanvas
In [283]: canvas
Out[283]: 
array([[ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
       [ 0.,  1.,  1.,  1.,  0.,  0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  1.,  0.,  0.,  0.,  0.,  0.,  0.],
       [ 1.,  0.,  0.,  1.,  0.,  0.,  0.,  0.,  0.,  0.],
       [ 1.,  0.,  0.,  1.,  0.,  0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.]])

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.