diff --git a/doc/source/whatsnew/v0.18.0.rst b/doc/source/whatsnew/v0.18.0.rst index 829c04dac9f2d..a05b9bb1a88ef 100644 --- a/doc/source/whatsnew/v0.18.0.rst +++ b/doc/source/whatsnew/v0.18.0.rst @@ -669,9 +669,9 @@ New signature .. ipython:: python - pd.Series([0,1]).rank(axis=0, method='average', numeric_only=None, + pd.Series([0,1]).rank(axis=0, method='average', numeric_only=False, na_option='keep', ascending=True, pct=False) - pd.DataFrame([0,1]).rank(axis=0, method='average', numeric_only=None, + pd.DataFrame([0,1]).rank(axis=0, method='average', numeric_only=False, na_option='keep', ascending=True, pct=False) diff --git a/doc/source/whatsnew/v1.4.0.rst b/doc/source/whatsnew/v1.4.0.rst index 7218c77e43409..a6960d266bb04 100644 --- a/doc/source/whatsnew/v1.4.0.rst +++ b/doc/source/whatsnew/v1.4.0.rst @@ -547,6 +547,7 @@ Other Deprecations - Deprecated :meth:`Categorical.replace`, use :meth:`Series.replace` instead (:issue:`44929`) - Deprecated :meth:`Index.__getitem__` with a bool key; use ``index.values[key]`` to get the old behavior (:issue:`44051`) - Deprecated downcasting column-by-column in :meth:`DataFrame.where` with integer-dtypes (:issue:`44597`) +- Deprecated ``numeric_only=None`` in :meth:`DataFrame.rank`; in a future version ``numeric_only`` must be either ``True`` or ``False`` (the default) (:issue:`45036`) - Deprecated :meth:`NaT.freq` (:issue:`45071`) - diff --git a/pandas/core/generic.py b/pandas/core/generic.py index fc15c846b1907..770e08ead31bb 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -8401,7 +8401,7 @@ def rank( self: NDFrameT, axis=0, method: str = "average", - numeric_only: bool_t | None = None, + numeric_only: bool_t | None | lib.NoDefault = lib.no_default, na_option: str = "keep", ascending: bool_t = True, pct: bool_t = False, @@ -8487,6 +8487,20 @@ def rank( 3 spider 8.0 4.0 4.0 4.0 1.000 4 snake NaN NaN NaN 5.0 NaN """ + warned = False + if numeric_only is None: + # GH#45036 + warnings.warn( + f"'numeric_only=None' in {type(self).__name__}.rank is deprecated " + "and will raise in a future version. Pass either 'True' or " + "'False'. 'False' will be the default.", + FutureWarning, + stacklevel=find_stack_level(), + ) + warned = True + elif numeric_only is lib.no_default: + numeric_only = None + axis = self._get_axis_number(axis) if na_option not in {"keep", "top", "bottom"}: @@ -8516,6 +8530,16 @@ def ranker(data): return ranker(self) except TypeError: numeric_only = True + if not warned: + # Only warn here if we didn't already issue a warning above + # GH#45036 + warnings.warn( + f"Dropping of nuisance columns in {type(self).__name__}.rank " + "is deprecated; in a future version this will raise TypeError. " + "Select only valid columns before calling rank.", + FutureWarning, + stacklevel=find_stack_level(), + ) if numeric_only: data = self._get_numeric_data() diff --git a/pandas/tests/frame/methods/test_rank.py b/pandas/tests/frame/methods/test_rank.py index 6c5831ad897d1..48188b66c45b5 100644 --- a/pandas/tests/frame/methods/test_rank.py +++ b/pandas/tests/frame/methods/test_rank.py @@ -136,7 +136,10 @@ def test_rank_mixed_frame(self, float_string_frame): float_string_frame["datetime"] = datetime.now() float_string_frame["timedelta"] = timedelta(days=1, seconds=1) - result = float_string_frame.rank(1) + with tm.assert_produces_warning(FutureWarning, match="numeric_only=None"): + float_string_frame.rank(numeric_only=None) + with tm.assert_produces_warning(FutureWarning, match="Dropping of nuisance"): + result = float_string_frame.rank(1) expected = float_string_frame.rank(1, numeric_only=True) tm.assert_frame_equal(result, expected) @@ -489,5 +492,7 @@ def test_rank_object_first(self, frame_or_series, na_option, ascending, expected ) def test_rank_mixed_axis_zero(self, data, expected): df = DataFrame(data) - result = df.rank() + msg = "Dropping of nuisance columns" + with tm.assert_produces_warning(FutureWarning, match=msg): + result = df.rank() tm.assert_frame_equal(result, expected)