Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Replacing numpy array elements with chained masks

Consider some array arr and advanced indexing mask mask:

import numpy as np

arr = np.arange(4).reshape(2, 2)
mask = A < 2

Using advanced indexing creates a new copy of an array. Accordingly, one cannot "chain" a mask with an an additional mask or even with a basic slicing operation to replace elements of an array:

submask = [False, True]
arr[mask][submask] = -1  # chaining 2 masks
arr[mask][:] = -1  # chaining a mask with a basic slicing operation

print(arr)
[[0 1]
 [2 3]]

I have two related questions:

1/ What is the best way to replace elements of an array using chained masks?

2/ If advanced indexing returns a copy of an array, why does the following work?

arr[mask] = -1

print(arr)
[[-1 -1]
 [ 2  3]]
like image 855
Bob Avatar asked Feb 05 '26 04:02

Bob


1 Answers

The short answer:

  • you have to figure out a way of combining the masks. Since masks can "chain" in different ways I don't think there's a simple all-purpose substitute.

  • indexing can either be a __getitem__ call, or a __setitem__. Your last case is a set.

With chained indexing, a[mask1][mask2] =value gets translated into

a.__getitem__(mask1).__setitem__(mask2, value)

Whether a gets modified or not depends on what the first getitem produces (a view vs copy).

In [11]: arr = np.arange(4).reshape(2,2)
In [12]: mask = arr<2
In [13]: mask
Out[13]: 
array([[ True,  True],
       [False, False]])
In [14]: arr[mask]
Out[14]: array([0, 1])

Indexing with a list or array may preserve the number of dimensions, but a boolean like this returns a 1d array, the items where the mask is true.

In your example, we could tweak the mask (details may vary with the intent of the 2nd mask):

In [15]: mask[:,0]=False
In [16]: mask
Out[16]: 
array([[False,  True],
       [False, False]])
In [17]: arr[mask]
Out[17]: array([1])
In [18]: arr[mask] += 10
In [19]: arr
Out[19]: 
array([[ 0, 11],
       [ 2,  3]])

Or a logical combination of masks:

In [26]: (np.arange(4).reshape(2,2)<2)&[False,True]
Out[26]: 
array([[False,  True],
       [False, False]])
like image 136
hpaulj Avatar answered Feb 07 '26 21:02

hpaulj



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!