diff --git a/doc/source/whatsnew/v3.0.0.rst b/doc/source/whatsnew/v3.0.0.rst index ca2ca07ff2fae..16be9e0a4fc34 100644 --- a/doc/source/whatsnew/v3.0.0.rst +++ b/doc/source/whatsnew/v3.0.0.rst @@ -280,6 +280,7 @@ Performance improvements Bug fixes ~~~~~~~~~ +- Fixed bug in :class:`SparseDtype` for equal comparison with na fill value. (:issue:`54770`) - Fixed bug in :meth:`DataFrame.join` inconsistently setting result index name (:issue:`55815`) - Fixed bug in :meth:`DataFrame.to_string` that raised ``StopIteration`` with nested DataFrames. (:issue:`16098`) - Fixed bug in :meth:`DataFrame.update` bool dtype being converted to object (:issue:`55509`) diff --git a/pandas/core/dtypes/dtypes.py b/pandas/core/dtypes/dtypes.py index 2bb2556c88204..f94d32a3b8547 100644 --- a/pandas/core/dtypes/dtypes.py +++ b/pandas/core/dtypes/dtypes.py @@ -1705,17 +1705,15 @@ def __eq__(self, other: object) -> bool: if isinstance(other, type(self)): subtype = self.subtype == other.subtype - if self._is_na_fill_value: + if self._is_na_fill_value or other._is_na_fill_value: # this case is complicated by two things: # SparseDtype(float, float(nan)) == SparseDtype(float, np.nan) # SparseDtype(float, np.nan) != SparseDtype(float, pd.NaT) # i.e. we want to treat any floating-point NaN as equal, but # not a floating-point NaN and a datetime NaT. - fill_value = ( - other._is_na_fill_value - and isinstance(self.fill_value, type(other.fill_value)) - or isinstance(other.fill_value, type(self.fill_value)) - ) + fill_value = isinstance( + self.fill_value, type(other.fill_value) + ) or isinstance(other.fill_value, type(self.fill_value)) else: with warnings.catch_warnings(): # Ignore spurious numpy warning diff --git a/pandas/tests/arrays/sparse/test_dtype.py b/pandas/tests/arrays/sparse/test_dtype.py index 6fcbfe96a3df7..6f0d41333f2fd 100644 --- a/pandas/tests/arrays/sparse/test_dtype.py +++ b/pandas/tests/arrays/sparse/test_dtype.py @@ -68,6 +68,14 @@ def test_nans_equal(): assert b == a +def test_nans_not_equal(): + # GH 54770 + a = SparseDtype(float, 0) + b = SparseDtype(float, pd.NA) + assert a != b + assert b != a + + with warnings.catch_warnings(): msg = "Allowing arbitrary scalar fill_value in SparseDtype is deprecated" warnings.filterwarnings("ignore", msg, category=FutureWarning) diff --git a/pandas/tests/extension/test_sparse.py b/pandas/tests/extension/test_sparse.py index c3a1d584170fb..cbca306ab0041 100644 --- a/pandas/tests/extension/test_sparse.py +++ b/pandas/tests/extension/test_sparse.py @@ -240,10 +240,6 @@ def test_fillna_limit_backfill(self, data_missing): super().test_fillna_limit_backfill(data_missing) def test_fillna_no_op_returns_copy(self, data, request): - if np.isnan(data.fill_value): - request.applymarker( - pytest.mark.xfail(reason="returns array with different fill value") - ) super().test_fillna_no_op_returns_copy(data) @pytest.mark.xfail(reason="Unsupported") @@ -400,6 +396,8 @@ def test_arith_frame_with_scalar(self, data, all_arithmetic_operators, request): "rmul", "floordiv", "rfloordiv", + "truediv", + "rtruediv", "pow", "mod", "rmod",