Skip to content

Commit 7e51bd7

Browse files
authored
BUG: handle NaNs in FloatingArray.equals (#44390)
1 parent 33daff1 commit 7e51bd7

File tree

3 files changed

+45
-0
lines changed

3 files changed

+45
-0
lines changed

doc/source/whatsnew/v1.4.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -719,6 +719,7 @@ Other
719719
- Bug in :meth:`RangeIndex.difference` with ``sort=None`` and ``step<0`` failing to sort (:issue:`44085`)
720720
- Bug in :meth:`Series.to_frame` and :meth:`Index.to_frame` ignoring the ``name`` argument when ``name=None`` is explicitly passed (:issue:`44212`)
721721
- Bug in :meth:`Series.replace` and :meth:`DataFrame.replace` with ``value=None`` and ExtensionDtypes (:issue:`44270`)
722+
- Bug in :meth:`FloatingArray.equals` failing to consider two arrays equal if they contain ``np.nan`` values (:issue:`44382`)
722723
-
723724

724725
.. ***DO NOT USE THIS SECTION***

pandas/core/arrays/masked.py

+15
Original file line numberDiff line numberDiff line change
@@ -627,6 +627,21 @@ def value_counts(self, dropna: bool = True) -> Series:
627627

628628
return Series(counts, index=index)
629629

630+
@doc(ExtensionArray.equals)
631+
def equals(self, other) -> bool:
632+
if type(self) != type(other):
633+
return False
634+
if other.dtype != self.dtype:
635+
return False
636+
637+
# GH#44382 if e.g. self[1] is np.nan and other[1] is pd.NA, we are NOT
638+
# equal.
639+
return np.array_equal(self._mask, other._mask) and np.array_equal(
640+
self._data[~self._mask],
641+
other._data[~other._mask],
642+
equal_nan=True,
643+
)
644+
630645
def _reduce(self, name: str, *, skipna: bool = True, **kwargs):
631646
if name in {"any", "all"}:
632647
return getattr(self, name)(skipna=skipna, **kwargs)

pandas/tests/arrays/floating/test_comparison.py

+29
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
import numpy as np
12
import pytest
23

34
import pandas as pd
45
import pandas._testing as tm
6+
from pandas.core.arrays import FloatingArray
57
from pandas.tests.arrays.masked_shared import (
68
ComparisonOps,
79
NumericOps,
@@ -34,3 +36,30 @@ def test_equals():
3436
a1 = pd.array([1, 2, None], dtype="Float64")
3537
a2 = pd.array([1, 2, None], dtype="Float32")
3638
assert a1.equals(a2) is False
39+
40+
41+
def test_equals_nan_vs_na():
42+
# GH#44382
43+
44+
mask = np.zeros(3, dtype=bool)
45+
data = np.array([1.0, np.nan, 3.0], dtype=np.float64)
46+
47+
left = FloatingArray(data, mask)
48+
assert left.equals(left)
49+
tm.assert_extension_array_equal(left, left)
50+
51+
assert left.equals(left.copy())
52+
assert left.equals(FloatingArray(data.copy(), mask.copy()))
53+
54+
mask2 = np.array([False, True, False], dtype=bool)
55+
data2 = np.array([1.0, 2.0, 3.0], dtype=np.float64)
56+
right = FloatingArray(data2, mask2)
57+
assert right.equals(right)
58+
tm.assert_extension_array_equal(right, right)
59+
60+
assert not left.equals(right)
61+
62+
# with mask[1] = True, the only difference is data[1], which should
63+
# not matter for equals
64+
mask[1] = True
65+
assert left.equals(right)

0 commit comments

Comments
 (0)