Numpy support

Numpy support#

Numpy functions that work on pint Quantity ndarray objects also work on PintArray.

In [1]: pa = PintArray([1, 2, np.nan, 4, 10], dtype="pint[m]")

In [2]: np.clip(pa, 3 * ureg.m, 5 * ureg.m)
Out[2]: 
<PintArray>
[3.0, 3.0, <NA>, 4.0, 5.0]
Length: 5, dtype: pint[meter][Float64]

Note that this function errors when applied to a Series.

In [3]: df = pd.DataFrame({"A": pa})

In [4]: np.clip(df['A'], 3 * ureg.m, 5 * ureg.m)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[4], line 1
----> 1 np.clip(df['A'], 3 * ureg.m, 5 * ureg.m)

File ~/checkouts/readthedocs.org/user_builds/pint-pandas/envs/latest/lib/python3.11/site-packages/pint/facets/numpy/quantity.py:75, in NumpyQuantity.__array_function__(self, func, types, args, kwargs)
     74 def __array_function__(self, func, types, args, kwargs):
---> 75     return numpy_wrap("function", func, args, kwargs, types)

File ~/checkouts/readthedocs.org/user_builds/pint-pandas/envs/latest/lib/python3.11/site-packages/pint/facets/numpy/numpy_func.py:1133, in numpy_wrap(func_type, func, args, kwargs, types)
   1131 if name not in handled or any(is_upcast_type(t) for t in types):
   1132     return NotImplemented
-> 1133 return handled[name](*args, **kwargs)

File ~/checkouts/readthedocs.org/user_builds/pint-pandas/envs/latest/lib/python3.11/site-packages/pint/facets/numpy/numpy_func.py:895, in implement_consistent_units_by_argument.<locals>.implementation(*args, **kwargs)
    893 for i, unwrapped_unit_arg in enumerate(unwrapped_unit_args):
    894     bound_args.arguments[valid_unit_arguments[i]] = unwrapped_unit_arg
--> 895 ret = func(*bound_args.args, **bound_args.kwargs)
    897 # Conditionally wrap output
    898 if wrap_output:

File ~/checkouts/readthedocs.org/user_builds/pint-pandas/envs/latest/lib/python3.11/site-packages/numpy/_core/fromnumeric.py:2296, in clip(a, a_min, a_max, out, min, max, **kwargs)
   2292 elif min is not np._NoValue or max is not np._NoValue:
   2293     raise ValueError("Passing `min` or `max` keyword argument when "
   2294                      "`a_min` and `a_max` are provided is forbidden.")
-> 2296 return _wrapfunc(a, 'clip', a_min, a_max, out=out, **kwargs)

File ~/checkouts/readthedocs.org/user_builds/pint-pandas/envs/latest/lib/python3.11/site-packages/numpy/_core/fromnumeric.py:51, in _wrapfunc(obj, method, *args, **kwds)
     49 bound = getattr(obj, method, None)
     50 if bound is None:
---> 51     return _wrapit(obj, method, *args, **kwds)
     53 try:
     54     return bound(*args, **kwds)

File ~/checkouts/readthedocs.org/user_builds/pint-pandas/envs/latest/lib/python3.11/site-packages/numpy/_core/fromnumeric.py:43, in _wrapit(obj, method, *args, **kwds)
     40 # As this already tried the method, subok is maybe quite reasonable here
     41 # but this follows what was done before. TODO: revisit this.
     42 arr, = conv.as_arrays(subok=False)
---> 43 result = getattr(arr, method)(*args, **kwds)
     45 return conv.wrap(result, to_scalar=False)

File ~/checkouts/readthedocs.org/user_builds/pint-pandas/envs/latest/lib/python3.11/site-packages/numpy/_core/_methods.py:113, in _clip(a, min, max, out, **kwargs)
    111     return um.maximum(a, min, out=out, **kwargs)
    112 else:
--> 113     return um.clip(a, min, max, out=out, **kwargs)

File pandas/_libs/missing.pyx:415, in pandas._libs.missing.NAType.__bool__()

TypeError: boolean value of NA is ambiguous

Apply the function to the PintArray instead of the Series using Series.values.

In [5]: np.clip(df['A'].values, 3 * ureg.m, 5 * ureg.m)
Out[5]: 
<PintArray>
[3.0, 3.0, <NA>, 4.0, 5.0]
Length: 5, dtype: pint[meter][Float64]