Mask an array by the index given from other array
Asked Answered
Y

5

5

I have the following arrays:

a = [10, 31, 30, 11, 17, 12, 22, 25, 85, 17, 21, 43]
b = [0, 1, 4, 6]

I want to mask a based on the index given by array b. That means getting:

c = [True, True, False, False, True, False, True, False, False, False, False, False]
Yammer answered 5/7, 2016 at 22:47 Comment(1)
Look into np.arange and np.in1d funcs.Clementius
I
3
In [524]: a=np.array([10, 31, 30, 11, 17, 12, 22, 25, 85, 17, 21, 43])
In [525]: b=np.array([0, 1, 4, 6])

To make a boolean c that is True at the b indices, just use:

In [526]: c=np.zeros(a.shape, bool)
In [527]: c[b]=True

In [528]: c
Out[528]: 
array([ True,  True, False, False,  True, False,  True, False, False,
       False, False, False], dtype=bool)

Then you can select the values of a with:

In [529]: a[c]
Out[529]: array([10, 31, 17, 22])

but you could just as well select them with b:

In [530]: a[b]
Out[530]: array([10, 31, 17, 22])

but c is better for removing those, a[~c]. np.delete(a,b) does the same thing.

Other array methods of generating c are

np.in1d(np.arange(a.shape[0]),b)
np.any(np.arange(a.shape[0])==b[:,None],0)

And since I was just discussing masked arrays in another question, I could do the same here:

In [542]: np.ma.MaskedArray(a,c)
Out[542]: 
masked_array(data = [-- -- 30 11 -- 12 -- 25 85 17 21 43],
             mask = [ True  True False False  True False  True False False False False False],
       fill_value = 999999)
Indigent answered 6/7, 2016 at 2:9 Comment(3)
Am I doing something wrong or does this not work with 2D arrays?Entophyte
@Yannic, I don't know what you doing or trying to do. But the masking that I demonstrated is easiest with 1d arrays. Somethings are different when working with 2+d arrays. If you are primarily trying to 'index', it would be a good idea to read the basic numpy documentation on the subject. It's a powerful concept, but it does take time to learn.Indigent
I found the solution here: zhangresearch.org/post/numpy-unravel-index You need to use "fancy indexing". First extract the column and row indices as separate lists like this: rows=coords[:,0] and cols=coords[:,1]. After that you can use arr[rows, cols] to get or modify multiple values in a 2d-array at once.Entophyte
F
2

Use np.in1d on a new array created with np.arange from the length of a:

>>> a = [10, 31, 30, 11, 17, 12, 22, 25, 85, 17, 21, 43]
>>> b = [0, 1, 4, 6]
>>> a = np.array(a)
>>> b = np.array(b)
>>> np.in1d(np.arange(len(a)), b)
array([ True,  True, False, False,  True, False,  True, False, False,
       False, False, False], dtype=bool)
Farrell answered 5/7, 2016 at 22:54 Comment(0)
S
2

It will be something like this:

c = []
for i, v in enumerate(a):
    mask = True if i in b else False
    c.append(mask)
Scruggs answered 5/7, 2016 at 22:58 Comment(2)
Thanks. Is there a way to return 'c' with the unmasked values of 'a' without changing its size?Yammer
You could append to c if False a tuple like (False, v) and should be it. Does that answer your question?Scruggs
E
1
res = [False] * len(a)
for idx in b:
    res[idx] = True

or

[idx in b for idx in range(len(a))]
Eastward answered 5/7, 2016 at 22:54 Comment(0)
E
0

For anyone who wants to use this for 2D-arrays or N-dimensional arrays:

I found the solution here: https://zhangresearch.org/post/numpy-unravel-index

In case the link goes dead some time in the future here is the approach:

You have to use "fancy indexing"

>>> a = np.arange(20).reshape(4, 5)
>>> print(a)
[[ 0  1  2  3  4]
 [ 5  6  7  8  9]
 [10 11 12 13 14]
 [15 16 17 18 19]]
>>> b = np.array([[0, 0], [0, 1], [0, 3], [1, 1], [2, 2]])
>>> print(b)
[[0 0]
 [0 1]
 [0 3]
 [1 1]
 [2 2]]
>>> b_x = b[:, 0]
>>> b_y = b[:, 1]
>>> print(b_x)
[0 0 0 1 2]
>>> print(b_y)
[0 1 3 1 2]

>>> print(a[b_x, b_y])
[ 0  1  3  6 12]
Entophyte answered 21/3, 2023 at 15:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.