pint-pandas icon indicating copy to clipboard operation
pint-pandas copied to clipboard

`numpy.allclose` not working for `PintArray`

Open rwijtvliet opened this issue 3 years ago • 1 comments

Issue

import pandas as pd
import numpy as np
from pint_pandas import PintArray

>>> pa1 = pa2 = PintArray([1, 45, -4.5], 'm')
>>> np.allclose(pa1, pa2)


# ---------------------------------------------------------------------------
# TypeError                                 Traceback (most recent call last)
#       16 pa = PintArray([1, 45, -4.5], 'm')
# ----> 17 np.allclose(pa1, pa2)

# <__array_function__ internals> in allclose(*args, **kwargs)

# ~\Anaconda3\envs\lb38\lib\site-packages\numpy\core\numeric.py in allclose(a, b, rtol, atol, equal_nan)
#    2248     """
# -> 2249     res = all(isclose(a, b, rtol=rtol, atol=atol, equal_nan=equal_nan))
#    2250     return bool(res)

# <__array_function__ internals> in isclose(*args, **kwargs)

# ~\Anaconda3\envs\lb38\lib\site-packages\numpy\core\numeric.py in isclose(a, b, rtol, atol, equal_nan)
#    2354 
# -> 2355     xfin = isfinite(x)
#    2356     yfin = isfinite(y)

# TypeError: ufunc 'isfinite' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''

I'm on pint version 0.18 and pint_pandas 0.2

Non-complete workaround

>>> pa1.quantity.units == pa2.quantity.units and np.allclose(pa1.quantity.m, pa2.quantity.m)
True

This is not watertight! Workaround incorrectly returns False when comparing 1 m with 100 cm.

Watertight (?) workaround


def pintarray_allclose(pa1, pa2):
    if pa1.quantity.dimensionality != pa2.quantity.dimensionality:
        return False
    a1 = pa1.quantity.magnitude
    a2 = pa2.astype(f"pint[{pa1.quantity.units}]").quantity.magnitude
    return np.allclose(a1, a2)

>>> pintarray_allclose(pa1, pa2)
True

>>> pintarray_allclose(pa1, pa2.astype('pint[km]'))
True

rwijtvliet avatar Jan 14 '22 18:01 rwijtvliet

this will need __array_function__ implemented

as a workaround you can use pint's quantity:

np.allclose(pa1.quantity, pa2.quantity) True

andrewgsavage avatar Jan 16 '22 02:01 andrewgsavage