55

I have a boolean mask array a of length n:

a = np.array([True, True, True, False, False])

I have a 2d array with n columns:

b = np.array([[1,2,3,4,5], [1,2,3,4,5]])

I want a new array which contains only the "True"-values, for example

c = ([[1,2,3], [1,2,3]])

c = a * b does not work because it contains also "0" for the false columns what I don't want

c = np.delete(b, a, 1) does not work

Any suggestions?

nbro
  • 15,395
  • 32
  • 113
  • 196
JohnDoe
  • 627
  • 2
  • 6
  • 6

3 Answers3

72

You probably want something like this:

>>> a = np.array([True, True, True, False, False])
>>> b = np.array([[1,2,3,4,5], [1,2,3,4,5]])
>>> b[:,a]
array([[1, 2, 3],
       [1, 2, 3]])

Note that for this kind of indexing to work, it needs to be an ndarray, like you were using, not a list, or it'll interpret the False and True as 0 and 1 and give you those columns:

>>> b[:,[True, True, True, False, False]]   
array([[2, 2, 2, 1, 1],
       [2, 2, 2, 1, 1]])
DSM
  • 342,061
  • 65
  • 592
  • 494
  • 3
    I've used this solution and it works well! But on scaling up to a `ndarray` of shape `(2800000,600)`, trying to use a mask with `200` `True` values is slow. Are there any optimisations? – jfive Apr 15 '16 at 21:41
  • 2.8M? Normally I would suggest just in time compiling - http://numba.pydata.org/ - not actually sure it will help here. – nycynik Mar 08 '19 at 01:22
  • 1
    Try `numpy.compress` (for bools) or `numpy.take` (for indices), see https://stackoverflow.com/q/46041811/882436 – Tom Apr 19 '19 at 14:00
  • 1
    I did calculate the mask and had to cast the mask to type `np.bool`. So I added `b[:,a.astype(np.bool)]` – Markus Weber Apr 29 '19 at 14:40
4

You can use numpy.ma module and use np.ma.masked_array function to do so.

>>> x = np.array([1, 2, 3, -1, 5])                                                
>>> mx = ma.masked_array(x, mask=[0, 0, 0, 1, 0])
masked_array(data=[1, 2, 3, --, 5], mask=[False, False,  False, True, False], fill_value=999999)
gibbone
  • 2,300
  • 20
  • 20
Magi
  • 341
  • 2
  • 15
0

Hope I'm not too late! Here's your array:

X = np.array([[1, 2, 3, 4, 5], 
              [1, 2, 3, 4, 5]])

Let's create an array of zeros of the same shape as X:

mask = np.zeros_like(X)
# array([[0, 0, 0, 0, 0],
#        [0, 0, 0, 0, 0]])

Then, specify the columns that you want to mask out or hide with a 1. In this case, we want the last 2 columns to be masked out.

mask[:, -2:] = 1
# array([[0, 0, 0, 1, 1],
#        [0, 0, 0, 1, 1]])

Create a masked array:

X_masked = np.ma.masked_array(X, mask)
# masked_array(data=[[1, 2, 3, --, --],
#                    [1, 2, 3, --, --]],
#              mask=[[False, False, False,  True,  True],
#                    [False, False, False,  True,  True]],
#              fill_value=999999)

We can then do whatever we want with X_masked, like taking the sum of each column (along axis=0):

np.sum(X_masked, axis=0)
# masked_array(data=[2, 4, 6, --, --],
#              mask=[False, False],
#              fill_value=1e+20)

Great thing about this is that X_masked is just a view of X, not a copy.

X_masked.base is X
# True
remykarem
  • 2,251
  • 22
  • 28