From aa81cd7e1aa7864b0d8223b7cbde5647905b7ab4 Mon Sep 17 00:00:00 2001 From: Brock Date: Wed, 30 Dec 2020 15:21:55 -0800 Subject: [PATCH 1/3] DEPR: try_cast kwarg in mask, where --- doc/source/whatsnew/v1.3.0.rst | 2 +- pandas/core/generic.py | 31 +++++++++++++++++------ pandas/core/internals/blocks.py | 21 ++++----------- pandas/core/internals/managers.py | 5 +--- pandas/tests/frame/indexing/test_mask.py | 13 ++++++++++ pandas/tests/frame/indexing/test_where.py | 12 +++++++++ 6 files changed, 55 insertions(+), 29 deletions(-) diff --git a/doc/source/whatsnew/v1.3.0.rst b/doc/source/whatsnew/v1.3.0.rst index 607a14c696578..28514c9a07d27 100644 --- a/doc/source/whatsnew/v1.3.0.rst +++ b/doc/source/whatsnew/v1.3.0.rst @@ -155,7 +155,7 @@ Deprecations - Deprecating allowing scalars passed to the :class:`Categorical` constructor (:issue:`38433`) - Deprecated allowing subclass-specific keyword arguments in the :class:`Index` constructor, use the specific subclass directly instead (:issue:`14093`,:issue:`21311`,:issue:`22315`,:issue:`26974`) - Deprecated ``astype`` of datetimelike (``timedelta64[ns]``, ``datetime64[ns]``, ``Datetime64TZDtype``, ``PeriodDtype``) to integer dtypes, use ``values.view(...)`` instead (:issue:`38544`) -- +- Deprecated keyword ``try_cast`` in :meth:`Series.where`, :meth:`Series.mask`, :meth:`DataFrame.where`, :meth:`DataFrame.mask`; cast results manually if desired (:issue:`??`) - .. --------------------------------------------------------------------------- diff --git a/pandas/core/generic.py b/pandas/core/generic.py index a7dfdb3cfbd97..2c4752f7e6262 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -8781,7 +8781,6 @@ def _where( axis=None, level=None, errors="raise", - try_cast=False, ): """ Equivalent to public method `where`, except that `other` is not @@ -8932,7 +8931,6 @@ def _where( cond=cond, align=align, errors=errors, - try_cast=try_cast, axis=block_axis, ) result = self._constructor(new_data) @@ -8954,7 +8952,7 @@ def where( axis=None, level=None, errors="raise", - try_cast=False, + try_cast=lib.no_default, ): """ Replace values where the condition is {cond_rev}. @@ -8989,6 +8987,9 @@ def where( try_cast : bool, default False Try to cast the result back to the input type (if possible). + .. deprecated:: 1.3.0 + Manually cast back if necessary. + Returns ------- Same type as caller or None if ``inplace=True``. @@ -9077,9 +9078,16 @@ def where( 4 True True """ other = com.apply_if_callable(other, self) - return self._where( - cond, other, inplace, axis, level, errors=errors, try_cast=try_cast - ) + + if try_cast is not lib.no_default: + warnings.warn( + "try_cast keyword is deprecated and will be removed in a " + "future version", + FutureWarning, + stacklevel=2, + ) + + return self._where(cond, other, inplace, axis, level, errors=errors) @final @doc( @@ -9098,12 +9106,20 @@ def mask( axis=None, level=None, errors="raise", - try_cast=False, + try_cast=lib.no_default, ): inplace = validate_bool_kwarg(inplace, "inplace") cond = com.apply_if_callable(cond, self) + if try_cast is not lib.no_default: + warnings.warn( + "try_cast keyword is deprecated and will be removed in a " + "future version", + FutureWarning, + stacklevel=2, + ) + # see gh-21891 if not hasattr(cond, "__invert__"): cond = np.array(cond) @@ -9114,7 +9130,6 @@ def mask( inplace=inplace, axis=axis, level=level, - try_cast=try_cast, errors=errors, ) diff --git a/pandas/core/internals/blocks.py b/pandas/core/internals/blocks.py index 76b30dc17711e..736a6ac248e94 100644 --- a/pandas/core/internals/blocks.py +++ b/pandas/core/internals/blocks.py @@ -1317,9 +1317,7 @@ def _maybe_reshape_where_args(self, values, other, cond, axis): return other, cond - def where( - self, other, cond, errors="raise", try_cast: bool = False, axis: int = 0 - ) -> List["Block"]: + def where(self, other, cond, errors="raise", axis: int = 0) -> List["Block"]: """ evaluate the block; return result block(s) from the result @@ -1330,7 +1328,6 @@ def where( errors : str, {'raise', 'ignore'}, default 'raise' - ``raise`` : allow exceptions to be raised - ``ignore`` : suppress exceptions. On error return original object - try_cast: bool, default False axis : int, default 0 Returns @@ -1369,9 +1366,7 @@ def where( # we cannot coerce, return a compat dtype # we are explicitly ignoring errors block = self.coerce_to_target_dtype(other) - blocks = block.where( - orig_other, cond, errors=errors, try_cast=try_cast, axis=axis - ) + blocks = block.where(orig_other, cond, errors=errors, axis=axis) return self._maybe_downcast(blocks, "infer") if not ( @@ -1852,9 +1847,7 @@ def shift( ) ] - def where( - self, other, cond, errors="raise", try_cast: bool = False, axis: int = 0 - ) -> List["Block"]: + def where(self, other, cond, errors="raise", axis: int = 0) -> List["Block"]: cond = _extract_bool_array(cond) assert not isinstance(other, (ABCIndex, ABCSeries, ABCDataFrame)) @@ -2102,9 +2095,7 @@ def to_native_types(self, na_rep="NaT", **kwargs): result = arr._format_native_types(na_rep=na_rep, **kwargs) return self.make_block(result) - def where( - self, other, cond, errors="raise", try_cast: bool = False, axis: int = 0 - ) -> List["Block"]: + def where(self, other, cond, errors="raise", axis: int = 0) -> List["Block"]: # TODO(EA2D): reshape unnecessary with 2D EAs arr = self.array_values().reshape(self.shape) @@ -2113,9 +2104,7 @@ def where( try: res_values = arr.T.where(cond, other).T except (ValueError, TypeError): - return super().where( - other, cond, errors=errors, try_cast=try_cast, axis=axis - ) + return super().where(other, cond, errors=errors, axis=axis) # TODO(EA2D): reshape not needed with 2D EAs res_values = res_values.reshape(self.values.shape) diff --git a/pandas/core/internals/managers.py b/pandas/core/internals/managers.py index 7dde952636a79..d44a3df45587a 100644 --- a/pandas/core/internals/managers.py +++ b/pandas/core/internals/managers.py @@ -542,9 +542,7 @@ def get_axe(block, qs, axes): def isna(self, func) -> "BlockManager": return self.apply("apply", func=func) - def where( - self, other, cond, align: bool, errors: str, try_cast: bool, axis: int - ) -> "BlockManager": + def where(self, other, cond, align: bool, errors: str, axis: int) -> "BlockManager": if align: align_keys = ["other", "cond"] else: @@ -557,7 +555,6 @@ def where( other=other, cond=cond, errors=errors, - try_cast=try_cast, axis=axis, ) diff --git a/pandas/tests/frame/indexing/test_mask.py b/pandas/tests/frame/indexing/test_mask.py index 23f3a18881782..8050769f56f6c 100644 --- a/pandas/tests/frame/indexing/test_mask.py +++ b/pandas/tests/frame/indexing/test_mask.py @@ -83,3 +83,16 @@ def test_mask_dtype_conversion(self): expected = bools.astype(float).mask(mask) result = bools.mask(mask) tm.assert_frame_equal(result, expected) + + +def test_mask_try_cast_deprecated(frame_or_series): + + obj = DataFrame(np.random.randn(4, 3)) + if frame_or_series is not DataFrame: + obj = obj[0] + + mask = obj > 0 + + with tm.assert_produces_warning(FutureWarning): + # try_cast keyword deprecated + obj.mask(mask, -1, try_cast=True) diff --git a/pandas/tests/frame/indexing/test_where.py b/pandas/tests/frame/indexing/test_where.py index 87d2fd37ab023..2f098426efaf9 100644 --- a/pandas/tests/frame/indexing/test_where.py +++ b/pandas/tests/frame/indexing/test_where.py @@ -672,3 +672,15 @@ def test_where_ea_other(self): expected["B"] = expected["B"].astype(object) result = df.where(mask, ser2, axis=1) tm.assert_frame_equal(result, expected) + + +def test_where_try_cast_deprecated(frame_or_series): + obj = DataFrame(np.random.randn(4, 3)) + if frame_or_series is not DataFrame: + obj = obj[0] + + mask = obj > 0 + + with tm.assert_produces_warning(FutureWarning): + # try_cast keyword deprecated + obj.where(mask, -1, try_cast=False) From 475d35868e7279b779945e9f233b47ffedc152bc Mon Sep 17 00:00:00 2001 From: Brock Date: Wed, 30 Dec 2020 15:23:16 -0800 Subject: [PATCH 2/3] update GH ref --- doc/source/whatsnew/v1.3.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v1.3.0.rst b/doc/source/whatsnew/v1.3.0.rst index 28514c9a07d27..461adf1299233 100644 --- a/doc/source/whatsnew/v1.3.0.rst +++ b/doc/source/whatsnew/v1.3.0.rst @@ -155,7 +155,7 @@ Deprecations - Deprecating allowing scalars passed to the :class:`Categorical` constructor (:issue:`38433`) - Deprecated allowing subclass-specific keyword arguments in the :class:`Index` constructor, use the specific subclass directly instead (:issue:`14093`,:issue:`21311`,:issue:`22315`,:issue:`26974`) - Deprecated ``astype`` of datetimelike (``timedelta64[ns]``, ``datetime64[ns]``, ``Datetime64TZDtype``, ``PeriodDtype``) to integer dtypes, use ``values.view(...)`` instead (:issue:`38544`) -- Deprecated keyword ``try_cast`` in :meth:`Series.where`, :meth:`Series.mask`, :meth:`DataFrame.where`, :meth:`DataFrame.mask`; cast results manually if desired (:issue:`??`) +- Deprecated keyword ``try_cast`` in :meth:`Series.where`, :meth:`Series.mask`, :meth:`DataFrame.where`, :meth:`DataFrame.mask`; cast results manually if desired (:issue:`38836`) - .. --------------------------------------------------------------------------- From 13e3b7589f2cc1979a9f2d2632bde093cf6d107b Mon Sep 17 00:00:00 2001 From: Brock Date: Wed, 30 Dec 2020 18:01:45 -0800 Subject: [PATCH 3/3] change default in docstring --- pandas/core/generic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 2c4752f7e6262..c3db8ef58deb6 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -8984,7 +8984,7 @@ def where( - 'raise' : allow exceptions to be raised. - 'ignore' : suppress exceptions. On error return original object. - try_cast : bool, default False + try_cast : bool, default None Try to cast the result back to the input type (if possible). .. deprecated:: 1.3.0