-
-
Notifications
You must be signed in to change notification settings - Fork 10.9k
ENH: Add __array_function__ implementation to MaskedArray #22913
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
ma_func = np.ma.__dict__.get(function.__name__, function) | ||
# Known incompatible functions | ||
# copy: np.copy() has subok semantics, which we can't pass through | ||
# unique: using ma.view(ndarray) internally doesn't work |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried using arr.view(np.ndarray)
within unique, but there are some expectations that a "masked" entity be returned. I would actually think that we want ma.unique()
to ignore the mask altogether and that isn't one of the unique elements.
For now, this seems easiest to just skip.
bb5bab8
to
9b7bc3c
Compare
incompatible_functions = {"copy", "unique"} | ||
# The masked functions know how to work with ndarray and | ||
# MaskedArrays, but can't guarantee anything about other types | ||
handled_types = {np.ndarray, MaskedArray} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if we want to allow subclasses or not, this is the safest for now... If we remove this limitation, then Astropy MaskedColumn
which is a subclass of MaskedArray
doesn't like the results.
Is this independent of #22914. |
Yes, it is independent of the |
@mattip, I just went and took a look at the Numpy 2.0 document thinking about proposing some of this MaskedArray work ( |
I started a hackmd document for the lightning talk here. Help fleshing it out would be more than welcome (it should be open for editing) |
Previously, calling np.stack(ma, a) with a masked and normal array would stack the nd-data from the items, but wrap it in a MaskedArray class without implementing the mask. This implementation intercepts the np.func calls and checks whether there is a compatible masked version that we can use instead. Now, the mask gets propagated with the stack as expected.
The manual masked implementation was largely copied over from the numpy array implementation just to handle masked concatenate. Now that we use array function implementations, we get that automatically with the np.diff() call, so there is no need to re-implement things in the masked namespace anymore.
9b7bc3c
to
50074f2
Compare
I decided to delve back into some of the masked array work again thinking it would still be nice to get some cleanups in for numpy 2.0. I think this one should be much less complicated than the ufunc PR, so I figured we should possibly focus on this before wading back over into the ufunc territory. As I rebased this there were some new failures that came up that illustrated a clear example where this would have helped. #22776 basically copy-pasted the main array implementation of |
In downstream libraries (Matplotlib), we frequently want to do array manipulation on whatever type is passed in.
xy = np.stack([x, y])
where x and y could be ndarray or MaskedArray. In certain places we handle this withstack = np.ma.stack if isinstance(x, MaskedArray) else np.stack
, but it isn't a very robust solution. Now that numpy as__array_function__
, we can handle the implementation within theMaskedArray
class if the specific function is available.Previously, calling
np.stack(ma, a)
with a masked and normal array would stack the nd-data from the items, but wrap it in aMaskedArray
class without applying the mask. This implementation intercepts thenp.func
calls and checks whether there is a compatible masked version that we can use instead. Now, the mask gets propagated with the stack as expected.closes #22338
closes #18675
possibly others...