Skip to content
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

Expected behavior of np.*_like functions #882

Open
jthielen opened this issue Sep 15, 2019 · 4 comments · May be fixed by #1669
Open

Expected behavior of np.*_like functions #882

jthielen opened this issue Sep 15, 2019 · 4 comments · May be fixed by #1669
Labels
numpy Numpy related bug/enhancement

Comments

@jthielen
Copy link
Contributor

Based on discussions in pydata/xarray#3238, it is unclear what the expected behavior of numpy functions like zeros_like, ones_like, and empty_like is with pint quantities (and depending on that behavior, how full_like should behave), in reference to their eventual __array_function__ implementation in pint.

The two possibilities discussed there were:

  • Have zeros_like, ones_like, and empty_like return base zeros, ones, or empty ndarrays, respectively, and have full_like simply match the unit of the fill_value argument
  • Have zeros_like, ones_like, and empty_like return quantities of zeros, ones, or empty in the same unit as the other argument
    • If this is expected behavior, should full_like
      • always have the unit of other
      • always have the unit of fill_value
      • have the unit of fill_value only if it matches dimensionality with other, raising an error otherwise
      • be tolerant of missing units on fill_value and other or not?

Relevant discussion quoted from pydata/xarray#3238:

@keewis:

I tried adding tests for zeros_like, ones_like and full_like, but I'm not sure what the expected result should look like, at least for the last one. I would assume zeros_like and ones_like return a quantity with the same unit as other, but what is the unit for full_like? The unit of other, or the unit of fill_value? Also, what happens if either of them has no unit, or both have units that are incompatible with each other?

@jthielen:

@keewis In andrewgsavage/pint#6, I implemented zeros_like, ones_like and empty_like to return base ndarrays rather than quantities, and full_like to have the unit of fill_value. This seemed like the most sensible behavior to me, since it avoids the ambiguities you mention in the full_like case if they were based on the unit of other, and for many of my own use cases, I've often wanted a zeros/ones array with a different unit than the quantity whose shape I am basing it off of.

Does this behavior seem reasonable to you? Also, would this be something that should be cleared up with an issue on pint's end?

@keewis:

I like your approach because it avoids all those issues, but stripping the units might be a surprise. Then again, what does a function named *_like promise? From the docs, it seems that only shape and dtype are guaranteed, so the question is whether or not the unit is part of the data or part of the type?

@jthielen:

@keewis My inclination is to think of the units as part of the data, and that, for example, zeros_like returning an array of bare zeros instead of zeros-with-units is reasonably intuitive. But since this is likely not everyone's perspective, I think raising an issue on pint's end would be good.

@jthielen
Copy link
Contributor Author

jthielen commented Dec 10, 2019

Based on the conversation in #905, this is being provisionally implemented with the first option ("Have zeros_like, ones_like, and empty_like return base zeros, ones, or empty ndarrays, respectively, and have full_like simply match the unit of the fill_value argument"). However, this will be revisited after seeing what usage is like in real codebases (so the issue can remain open).

@keewis
Copy link
Contributor

keewis commented Sep 29, 2022

it turns out that the current definition of ones_like (and, to some extent, zeros_like) is inconvenient (see pydata/xarray#7067 (comment)).

What if we defined those as:

zeros_like(q) == full_like(q, fill_value=Quantity(0, q.units))
ones_like(q) == full_like(q, fill_value=Quantity(1, q.units))

and keep full_like as is?

What do you think, @jthielen?

Edit: the appropriate non-quantity can still be created using full_like(q, fill_value=0) or zeros_like(q.magnitude)

@jthielen
Copy link
Contributor Author

it turns out that the current definition of ones_like (and, to some extent, zeros_like) is inconvenient (see pydata/xarray#7067 (comment)).

What if we defined those as:

zeros_like(q) == full_like(q, fill_value=Quantity(0, q.units))
ones_like(q) == full_like(q, fill_value=Quantity(1, q.units))

and keep full_like as is?

What do you think, @jthielen?

No opposition from me! The initial implementation was based on what made sense at the time, but was provisional based on not yet seeing what usage was like in real codebases.

Would pint need some form of deprecation cycle for this change in behavior, or can we assume that usage of these functions was uncommon due to unclear expected behavior?

@keewis
Copy link
Contributor

keewis commented Sep 29, 2022

Would pint need some form of deprecation cycle for this change in behavior, or can we assume that usage of these functions was uncommon due to unclear expected behavior?

Not sure. However, given that getting that result is basically just the result of the underlying array (and the alternative is backwards compatible) I'd say the only thing necessary is to clearly document that in the release notes?

For reference, instead of

ones_like(q)

we'd need to use

ones_like(q.magnitude)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
numpy Numpy related bug/enhancement
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants