hgrecco / pint-pandas

Pandas support for pint
Other
169 stars 42 forks source link

negating (using `__neg__`) not working #100

Closed rwijtvliet closed 3 months ago

rwijtvliet commented 2 years ago
import pandas as pd
import numpy as np
import pint
import pint_pandas

# For reference: __neg__ on Series without units.
# -----------------------------------------------

# Input:
s_plain = pd.Series(np.random.rand(2), index=['a', 'b'])
# a    0.380723
# b    0.777449
# dtype: float64

# Output:
-s_plain
# a   -0.380723
# b   -0.777449
# dtype: float64

# Issue: __neg__ on Series with pint dtype.
# -----------------------------------------

# Input:
s_units = s_plain.astype('pint[MWh]')
# ...\Software\Anaconda\envs\lb38\lib\site-packages\pint_pandas\pint_array.py:648: UnitStrippedWarning: The unit of the quantity is stripped when downcasting to ndarray.
#   return np.array(qtys, dtype="object", copy=copy)
# a      0.380723445919278
# b     0.7774489057875323
# dtype: pint[megawatt_hour]

# Won't work:
-s_units # TypeError: Unary negative expects numeric dtype, not pint[megawatt_hour]

# Expected:
# a      -0.380723445919278
# b     -0.7774489057875323
# dtype: pint[megawatt_hour] 

# versions:
{'numpy': '1.20.1', 'pandas': '1.2.4', 'pint': '0.18', 'pint_pandas': '0.2'}
rwijtvliet commented 2 years ago

Workaround

Basically, recreate the Series. Maybe it's helpful in the bugfix.

# Workaround:
pd.Series(-s_units.pint.m).astype(f'pint[{s_units.pint.units}]')
# a      -0.380723445919278
# b     -0.7774489057875323
# dtype: pint[megawatt_hour]

For Dataframes, an issue with __neg__ also exists, but slightly different. Also, the workaround is a bit more readable and doesn't require referencing the object twice:

(-df.pint.dequantify()).pint.quantify()
MichaelTiemannOSC commented 10 months ago

Looks like the starting point for a PR here would be in Pandas, pandas/core/arrays/base.py ExtensionOpsMixin and the definition of a _create_unary_arith_method or some such.