Skip to content

Commit 41f22b3

Browse files
Backport PR #56769 on branch 2.2.x (BUG: replace matching Floats with bools for ea dtypes) (#56780)
Backport PR #56769: BUG: replace matching Floats with bools for ea dtypes Co-authored-by: Patrick Hoefler <[email protected]>
1 parent 57079b6 commit 41f22b3

File tree

3 files changed

+41
-14
lines changed

3 files changed

+41
-14
lines changed

doc/source/whatsnew/v2.2.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -789,6 +789,7 @@ Numeric
789789
- Bug in :meth:`Series.__floordiv__` and :meth:`Series.__truediv__` for :class:`ArrowDtype` with integral dtypes raising for large divisors (:issue:`56706`)
790790
- Bug in :meth:`Series.__floordiv__` for :class:`ArrowDtype` with integral dtypes raising for large values (:issue:`56645`)
791791
- Bug in :meth:`Series.pow` not filling missing values correctly (:issue:`55512`)
792+
- Bug in :meth:`Series.replace` and :meth:`DataFrame.replace` matching float ``0.0`` with ``False`` and vice versa (:issue:`55398`)
792793

793794
Conversion
794795
^^^^^^^^^^

pandas/core/missing.py

+28-14
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
from pandas.core.dtypes.cast import infer_dtype_from
3232
from pandas.core.dtypes.common import (
3333
is_array_like,
34+
is_bool_dtype,
3435
is_numeric_dtype,
3536
is_numeric_v_string_like,
3637
is_object_dtype,
@@ -100,21 +101,34 @@ def mask_missing(arr: ArrayLike, values_to_mask) -> npt.NDArray[np.bool_]:
100101

101102
# GH 21977
102103
mask = np.zeros(arr.shape, dtype=bool)
103-
for x in nonna:
104-
if is_numeric_v_string_like(arr, x):
105-
# GH#29553 prevent numpy deprecation warnings
106-
pass
107-
else:
108-
if potential_na:
109-
new_mask = np.zeros(arr.shape, dtype=np.bool_)
110-
new_mask[arr_mask] = arr[arr_mask] == x
104+
if (
105+
is_numeric_dtype(arr.dtype)
106+
and not is_bool_dtype(arr.dtype)
107+
and is_bool_dtype(nonna.dtype)
108+
):
109+
pass
110+
elif (
111+
is_bool_dtype(arr.dtype)
112+
and is_numeric_dtype(nonna.dtype)
113+
and not is_bool_dtype(nonna.dtype)
114+
):
115+
pass
116+
else:
117+
for x in nonna:
118+
if is_numeric_v_string_like(arr, x):
119+
# GH#29553 prevent numpy deprecation warnings
120+
pass
111121
else:
112-
new_mask = arr == x
113-
114-
if not isinstance(new_mask, np.ndarray):
115-
# usually BooleanArray
116-
new_mask = new_mask.to_numpy(dtype=bool, na_value=False)
117-
mask |= new_mask
122+
if potential_na:
123+
new_mask = np.zeros(arr.shape, dtype=np.bool_)
124+
new_mask[arr_mask] = arr[arr_mask] == x
125+
else:
126+
new_mask = arr == x
127+
128+
if not isinstance(new_mask, np.ndarray):
129+
# usually BooleanArray
130+
new_mask = new_mask.to_numpy(dtype=bool, na_value=False)
131+
mask |= new_mask
118132

119133
if na_mask.any():
120134
mask |= isna(arr)

pandas/tests/series/methods/test_replace.py

+12
Original file line numberDiff line numberDiff line change
@@ -799,3 +799,15 @@ def test_replace_numeric_column_with_na(self, val):
799799

800800
ser.replace(to_replace=1, value=pd.NA, inplace=True)
801801
tm.assert_series_equal(ser, expected)
802+
803+
def test_replace_ea_float_with_bool(self):
804+
# GH#55398
805+
ser = pd.Series([0.0], dtype="Float64")
806+
expected = ser.copy()
807+
result = ser.replace(False, 1.0)
808+
tm.assert_series_equal(result, expected)
809+
810+
ser = pd.Series([False], dtype="boolean")
811+
expected = ser.copy()
812+
result = ser.replace(0.0, True)
813+
tm.assert_series_equal(result, expected)

0 commit comments

Comments
 (0)