From 0f4634dc3432826be3f9cdb5e0badf93ed29212c Mon Sep 17 00:00:00 2001 From: Simon Hawkins Date: Thu, 17 Mar 2022 13:31:00 +0000 Subject: [PATCH 1/2] REGR: DataFrame.replace when the replacement value was explitly None --- doc/source/whatsnew/v1.4.2.rst | 1 + pandas/core/internals/blocks.py | 7 +++++++ pandas/tests/frame/methods/test_replace.py | 14 ++++++++++++++ 3 files changed, 22 insertions(+) diff --git a/doc/source/whatsnew/v1.4.2.rst b/doc/source/whatsnew/v1.4.2.rst index 3523f691cae8f..7d63f36b11d43 100644 --- a/doc/source/whatsnew/v1.4.2.rst +++ b/doc/source/whatsnew/v1.4.2.rst @@ -19,6 +19,7 @@ Fixed regressions - Fixed memory performance regression in :meth:`Series.fillna` when called on a :class:`DataFrame` column with ``inplace=True`` (:issue:`46149`) - Provided an alternative solution for passing custom Excel formats in :meth:`.Styler.to_excel`, which was a regression based on stricter CSS validation. Examples available in the documentation for :meth:`.Styler.format` (:issue:`46152`) - Fixed regression in :meth:`DataFrame.replace` when a replacement value was also a target for replacement (:issue:`46306`) +- Fixed regression in :meth:`DataFrame.replace` when the replacement value was explitly ``None`` when passed in a dictionary to ``to_replace`` (:issue:`45601`, :issue:`45836`) - Fixed regression when setting values with :meth:`DataFrame.loc` losing :class:`MultiIndex` names if :class:`DataFrame` was empty before (:issue:`46317`) - diff --git a/pandas/core/internals/blocks.py b/pandas/core/internals/blocks.py index 69f66973d0954..168b41652b735 100644 --- a/pandas/core/internals/blocks.py +++ b/pandas/core/internals/blocks.py @@ -778,6 +778,13 @@ def _replace_coerce( mask=mask, ) else: + if value is None: + # gh-45601, gh-45836 + nb = self.astype(np.dtype(object), copy=False) + if nb is self and not inplace: + nb = nb.copy() + putmask_inplace(nb.values, mask, value) + return [nb] return self.replace( to_replace=to_replace, value=value, inplace=inplace, mask=mask ) diff --git a/pandas/tests/frame/methods/test_replace.py b/pandas/tests/frame/methods/test_replace.py index 2eb300a8905b8..da13f2c16064e 100644 --- a/pandas/tests/frame/methods/test_replace.py +++ b/pandas/tests/frame/methods/test_replace.py @@ -676,6 +676,20 @@ def test_replace_numpy_nan(self, nulls_fixture): result = df.replace(to_replace, value).astype(dtype=dtype) tm.assert_frame_equal(result, expected) + def test_replace_NA_with_None(self): + # gh-45601 + df = DataFrame({"value": [42, None]}).astype({"value": "Int64"}) + result = df.replace({pd.NA: None}) + expected = DataFrame({"value": [42, None]}, dtype=object) + tm.assert_frame_equal(result, expected) + + def test_replace_NAT_with_None(self): + # gh-45836 + df = DataFrame([pd.NaT, pd.NaT]) + result = df.replace({pd.NaT: None, np.NaN: None}) + expected = DataFrame([None, None]) + tm.assert_frame_equal(result, expected) + def test_replace_value_is_none(self, datetime_frame): orig_value = datetime_frame.iloc[0, 0] orig2 = datetime_frame.iloc[1, 0] From 426741b359a9ac86181b8964b9a061a35aa35260 Mon Sep 17 00:00:00 2001 From: Simon Hawkins Date: Thu, 17 Mar 2022 13:43:53 +0000 Subject: [PATCH 2/2] typo --- doc/source/whatsnew/v1.4.2.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v1.4.2.rst b/doc/source/whatsnew/v1.4.2.rst index 7d63f36b11d43..4cbb8118055af 100644 --- a/doc/source/whatsnew/v1.4.2.rst +++ b/doc/source/whatsnew/v1.4.2.rst @@ -19,7 +19,7 @@ Fixed regressions - Fixed memory performance regression in :meth:`Series.fillna` when called on a :class:`DataFrame` column with ``inplace=True`` (:issue:`46149`) - Provided an alternative solution for passing custom Excel formats in :meth:`.Styler.to_excel`, which was a regression based on stricter CSS validation. Examples available in the documentation for :meth:`.Styler.format` (:issue:`46152`) - Fixed regression in :meth:`DataFrame.replace` when a replacement value was also a target for replacement (:issue:`46306`) -- Fixed regression in :meth:`DataFrame.replace` when the replacement value was explitly ``None`` when passed in a dictionary to ``to_replace`` (:issue:`45601`, :issue:`45836`) +- Fixed regression in :meth:`DataFrame.replace` when the replacement value was explicitly ``None`` when passed in a dictionary to ``to_replace`` (:issue:`45601`, :issue:`45836`) - Fixed regression when setting values with :meth:`DataFrame.loc` losing :class:`MultiIndex` names if :class:`DataFrame` was empty before (:issue:`46317`) -