Skip to content

BUG: Masked object array of ndarrays attaches mask to masked array value #8906

Open

Description

@eric-wieser

See below

>>> m = np.ma.array([None], mask=[False])

>>> m[0] = np.ma.masked; m[0]
masked

>>> m[0] = np.eye(3); m[0]
array([[ 1.,  0.,  0.],
       [ 0.,  1.,  0.],
       [ 0.,  0.,  1.]])

>>> m[0] = np.ma.masked; m[0]
masked_array(data =
 [[-- -- --]
 [-- -- --]
 [-- -- --]],
             mask =
 [[ True  True  True]
 [ True  True  True]
 [ True  True  True]],
       fill_value = 1e+20)   # but that was the same line that we ran above!

The culprit is the # Did we extract a single item? check in numpy/ma/core.py:3192.

I just don't think we have the information needed to actually know whether we got a single item from self.data, which could be of any subclass (?).

Maybe the code should become something like:

# Normalize the index. This is wrong, but being right is really hard (#8276)
if not isinstance(idx, tuple): 
    idx = (idx,)

# append an ellipsis if there was not already one, and remember whether we did
could_be_scalar = Ellipsis not in idx
if could_be_scalar:
    idx = idx + (Ellipsis,)

# guaranteed to be a (possibly 0d) array and not a scalar element
dout = data[idx]

# flatten 0d arrays that were not requested
if could_be_scalar and dout.ndim == 0:
    result = result[()]
return result

#8276 (comment) for the lazy

Activity

  1. eric-wieser commented on Apr 19, 2017

    @eric-wieser
    MemberAuthor

    I think I remember seeing that this is actually intended behaviour in the docs somewhere, but can no longer find where. Anyone else remember this being desirable?

  2. eric-wieser commented on Apr 19, 2017

    @eric-wieser
    MemberAuthor

    Found it: 1.10 release notes, introduced in 1a4d943 (#5962)

    Masked arrays containing objects with arrays
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    For such (rare) masked arrays, getting a single masked item no longer returns a
    corrupted masked array, but a fully masked version of the item.
    

    @mhvk: What was the rationale for not just returning masked?

  3. mhvk commented on Apr 19, 2017

    @mhvk
    Contributor

    Yikes, that PR coming back to bite again: as you will have seen, it was an unintended consequence of what was quite a nice simplification of MaskedArray.__getitem__. I'm afraid I do not really recall the reason for what I did in #5962, but from rereading it, it seems to have been important that whatever was returned had a length, and len(np.ma.masked) would fail.

  4. eric-wieser commented on Apr 19, 2017

    @eric-wieser
    MemberAuthor

    it seems to have been important that whatever was returned had a __len__

    This doesn't sound like something that we should guarantee - we don't guarantee anything else about the properties of the returned value - and it seems like if you're using a masked object array, it's your responsibility to handle masked return values.

    Would you be in favor of reverting this in #8905, where the original bug is fixed properly?

  5. eric-wieser commented on Apr 15, 2019

    @eric-wieser
    MemberAuthor

    Still present

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions