-
Notifications
You must be signed in to change notification settings - Fork 49
Description
Problem
Calling .pint.ito()
from a Series object should allow for changing its units, but it just does nothing. Minimal reproducible example:
import pandas as pd
import pint_pandas
s = pd.Series([1.0, 2.0], dtype="pint[m]")
print(s)
s.pint.ito('cm')
print(s)
Output:
0 1.0
1 2.0
dtype: pint[meter][Float64]
0 1.0
1 2.0
dtype: pint[meter][Float64]
Origin
I figured out the problem arises in pint_array.DelegatedMethod.__get__()
, where the called method (here ito()
) is delegated to an instance of Quantity
(created in pint_array.PintSeriesAccessor.__init__()
) that is independent of the calling Series object. As a result, any inplace modification is lost.
Potential solution
A solution would consist in re-initializing the calling Series object with quantity
magnitude and units after result = method(*args, **kwargs)
in pint_array.DelegatedMethod.__get__()
. I.e., add:
q = object.__getattribute__(obj, "quantity")
po = object.__getattribute__(obj, "pandas_obj")
dtype = PintType(units=q.units, subdtype=q.dtype)
po.__init__(q.magnitude, dtype=dtype)
Note that the change in units implies a change in the Series dtype
, which is why a complete Series re-initialization is needed, and not just an update of the underlying PintArray data. With this modification, I get the expected output:
0 1.0
1 2.0
dtype: pint[meter][Float64]
0 100.0
1 200.0
dtype: pint[centimeter][float64]
Would this be good for a PR?
PS: if we only want to re-initialize when it is really necessary, we could imagine a solution with a new boolean attribute in the Delegated class such as reinitialize
, which will be set to True only for those methods that require it. Let me know if you want me to work on a PR with that.