pythonnumpymasked-array

Express 1d masked array as list of slices


I have a 1d numpy array with booleans values (mask) which I would like to convert into a list of slices where the mask is True, e.g.:

mask = [False, True, True, True, False, False, True, True]

and I would like to obtain

[slice(1, 4, None), slice(6, 8, None)]

The numpy masked array operations (in particular np.ma.clump_masked()) can do that, but the only way I found to use it would be to do the following:

np.ma.clump_masked(np.ma.masked_array(np.ones_like(mask), mask))

which yields exactly what I'm looking for:

[slice(1, 4, None), slice(6, 8, None)]

i.e., generating an array with the same shape as mask, applying the mask to it, and then computing mask_clumped() on that.

However, the np.ma.masked_array(np.ones_like(mask), mask)-step seems unnecessary to me. Is there any way to obtain the list of slices from a simplified operation which I would imagine to look like the following?

np.ma.clump_masked(mask)

Solution

  • np.ma.masked_array requires a masked array as input, not an ndarray. One approach is to do what you're currently doing and create a masked array

    import numpy as np
    mask = np.asarray([False, True, True, True, False, False, True, True])
    masked_array = np.ma.masked_array(data=mask, mask=mask)
    np.ma.clump_masked(masked_array)
    

    However, I assume you're generating mask based on some condition? In which case, you can use np.ma.masked_where. For example, to get all the slices of each even number from 0 to 9:

    import numpy as np
    arr = np.arange(10)
    masked_arr = np.ma.masked_where(arr % 2 == 0, arr)
    np.ma.clump_masked(masked_arr)
    

    which outputs:

    [slice(0, 1, None),
     slice(2, 3, None),
     slice(4, 5, None),
     slice(6, 7, None),
     slice(8, 9, None)]
    

    There are other functions such as np.ma.masked_inside which will create a masked array and mask all elements within some interval. Check the 'see also' of the masked_where docs for a list of the related funcitons.