diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 44320de2c3209..efd3fff91d15a 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -204,7 +204,6 @@ from pandas._typing import ( AggFuncType, - AlignJoin, AnyAll, AnyArrayLike, ArrayLike, @@ -218,7 +217,6 @@ Dtype, DtypeObj, FilePath, - FillnaOptions, FloatFormatType, FormattersType, Frequency, @@ -228,7 +226,6 @@ Level, MergeHow, NaPosition, - NDFrameT, PythonFuncType, QuantileInterpolation, ReadBuffer, @@ -238,8 +235,6 @@ SortKind, StorageOptions, Suffixes, - TimedeltaConvertibleTypes, - TimestampConvertibleTypes, ValueKeyFunc, WriteBuffer, npt, @@ -248,7 +243,6 @@ from pandas.core.groupby.generic import DataFrameGroupBy from pandas.core.interchange.dataframe_protocol import DataFrame as DataFrameXchg from pandas.core.internals import SingleDataManager - from pandas.core.resample import Resampler from pandas.io.formats.style import Styler @@ -4954,33 +4948,6 @@ def _reindex_multi( fill_value=fill_value, ) - @doc(NDFrame.align, **_shared_doc_kwargs) - def align( - self, - other: NDFrameT, - join: AlignJoin = "outer", - axis: Axis | None = None, - level: Level = None, - copy: bool | None = None, - fill_value=None, - method: FillnaOptions | None | lib.NoDefault = lib.no_default, - limit: int | None | lib.NoDefault = lib.no_default, - fill_axis: Axis | lib.NoDefault = lib.no_default, - broadcast_axis: Axis | None | lib.NoDefault = lib.no_default, - ) -> tuple[Self, NDFrameT]: - return super().align( - other, - join=join, - axis=axis, - level=level, - copy=copy, - fill_value=fill_value, - method=method, - limit=limit, - fill_axis=fill_axis, - broadcast_axis=broadcast_axis, - ) - @Appender( """ Examples @@ -5005,7 +4972,8 @@ def align( """ ) @Substitution( - **_shared_doc_kwargs, + klass=_shared_doc_kwargs["klass"], + axes_single_arg=_shared_doc_kwargs["axes_single_arg"], extended_summary_sub=" column or", axis_description_sub=", and 1 identifies the columns", see_also_sub=" or columns", @@ -5025,7 +4993,7 @@ def set_axis( klass=_shared_doc_kwargs["klass"], optional_reindex=_shared_doc_kwargs["optional_reindex"], ) - def reindex( # type: ignore[override] + def reindex( self, labels=None, *, @@ -5427,65 +5395,6 @@ def rename( errors=errors, ) - @overload - def fillna( - self, - value: Hashable | Mapping | Series | DataFrame = ..., - *, - method: FillnaOptions | None = ..., - axis: Axis | None = ..., - inplace: Literal[False] = ..., - limit: int | None = ..., - downcast: dict | None = ..., - ) -> DataFrame: - ... - - @overload - def fillna( - self, - value: Hashable | Mapping | Series | DataFrame = ..., - *, - method: FillnaOptions | None = ..., - axis: Axis | None = ..., - inplace: Literal[True], - limit: int | None = ..., - downcast: dict | None = ..., - ) -> None: - ... - - @overload - def fillna( - self, - value: Hashable | Mapping | Series | DataFrame = ..., - *, - method: FillnaOptions | None = ..., - axis: Axis | None = ..., - inplace: bool = ..., - limit: int | None = ..., - downcast: dict | None = ..., - ) -> DataFrame | None: - ... - - @doc(NDFrame.fillna, **_shared_doc_kwargs) - def fillna( - self, - value: Hashable | Mapping | Series | DataFrame = None, - *, - method: FillnaOptions | None = None, - axis: Axis | None = None, - inplace: bool = False, - limit: int | None = None, - downcast: dict | None = None, - ) -> DataFrame | None: - return super().fillna( - value=value, - method=method, - axis=axis, - inplace=inplace, - limit=limit, - downcast=downcast, - ) - def pop(self, item: Hashable) -> Series: """ Return item and drop from frame. Raise KeyError if not found. @@ -5529,52 +5438,6 @@ def pop(self, item: Hashable) -> Series: """ return super().pop(item=item) - @overload - def replace( - self, - to_replace=..., - value=..., - *, - inplace: Literal[False] = ..., - limit: int | None = ..., - regex: bool = ..., - method: Literal["pad", "ffill", "bfill"] | lib.NoDefault = ..., - ) -> DataFrame: - ... - - @overload - def replace( - self, - to_replace=..., - value=..., - *, - inplace: Literal[True], - limit: int | None = ..., - regex: bool = ..., - method: Literal["pad", "ffill", "bfill"] | lib.NoDefault = ..., - ) -> None: - ... - - @doc(NDFrame.replace, **_shared_doc_kwargs) - def replace( - self, - to_replace=None, - value=lib.no_default, - *, - inplace: bool = False, - limit: int | None = None, - regex: bool = False, - method: Literal["pad", "ffill", "bfill"] | lib.NoDefault = lib.no_default, - ) -> DataFrame | None: - return super().replace( - to_replace=to_replace, - value=value, - inplace=inplace, - limit=limit, - regex=regex, - method=method, - ) - def _replace_columnwise( self, mapping: dict[Hashable, tuple[Any, Any]], inplace: bool, regex ): @@ -6692,9 +6555,6 @@ def sort_values( ) -> None: ... - # TODO: Just move the sort_values doc here. - @Substitution(**_shared_doc_kwargs) - @Appender(NDFrame.sort_values.__doc__) def sort_values( self, by: IndexLabel, @@ -6707,6 +6567,154 @@ def sort_values( ignore_index: bool = False, key: ValueKeyFunc = None, ) -> DataFrame | None: + """ + Sort by the values along either axis. + + Parameters + ---------- + by : str or list of str + Name or list of names to sort by. + + - if `axis` is 0 or `'index'` then `by` may contain index + levels and/or column labels. + - if `axis` is 1 or `'columns'` then `by` may contain column + levels and/or index labels. + axis : "{0 or 'index', 1 or 'columns'}", default 0 + Axis to be sorted. + ascending : bool or list of bool, default True + Sort ascending vs. descending. Specify list for multiple sort + orders. If this is a list of bools, must match the length of + the by. + inplace : bool, default False + If True, perform operation in-place. + kind : {'quicksort', 'mergesort', 'heapsort', 'stable'}, default 'quicksort' + Choice of sorting algorithm. See also :func:`numpy.sort` for more + information. `mergesort` and `stable` are the only stable algorithms. For + DataFrames, this option is only applied when sorting on a single + column or label. + na_position : {'first', 'last'}, default 'last' + Puts NaNs at the beginning if `first`; `last` puts NaNs at the + end. + ignore_index : bool, default False + If True, the resulting axis will be labeled 0, 1, …, n - 1. + key : callable, optional + Apply the key function to the values + before sorting. This is similar to the `key` argument in the + builtin :meth:`sorted` function, with the notable difference that + this `key` function should be *vectorized*. It should expect a + ``Series`` and return a Series with the same shape as the input. + It will be applied to each column in `by` independently. + + .. versionadded:: 1.1.0 + + Returns + ------- + DataFrame or None + DataFrame with sorted values or None if ``inplace=True``. + + See Also + -------- + DataFrame.sort_index : Sort a DataFrame by the index. + Series.sort_values : Similar method for a Series. + + Examples + -------- + >>> df = pd.DataFrame({ + ... 'col1': ['A', 'A', 'B', np.nan, 'D', 'C'], + ... 'col2': [2, 1, 9, 8, 7, 4], + ... 'col3': [0, 1, 9, 4, 2, 3], + ... 'col4': ['a', 'B', 'c', 'D', 'e', 'F'] + ... }) + >>> df + col1 col2 col3 col4 + 0 A 2 0 a + 1 A 1 1 B + 2 B 9 9 c + 3 NaN 8 4 D + 4 D 7 2 e + 5 C 4 3 F + + Sort by col1 + + >>> df.sort_values(by=['col1']) + col1 col2 col3 col4 + 0 A 2 0 a + 1 A 1 1 B + 2 B 9 9 c + 5 C 4 3 F + 4 D 7 2 e + 3 NaN 8 4 D + + Sort by multiple columns + + >>> df.sort_values(by=['col1', 'col2']) + col1 col2 col3 col4 + 1 A 1 1 B + 0 A 2 0 a + 2 B 9 9 c + 5 C 4 3 F + 4 D 7 2 e + 3 NaN 8 4 D + + Sort Descending + + >>> df.sort_values(by='col1', ascending=False) + col1 col2 col3 col4 + 4 D 7 2 e + 5 C 4 3 F + 2 B 9 9 c + 0 A 2 0 a + 1 A 1 1 B + 3 NaN 8 4 D + + Putting NAs first + + >>> df.sort_values(by='col1', ascending=False, na_position='first') + col1 col2 col3 col4 + 3 NaN 8 4 D + 4 D 7 2 e + 5 C 4 3 F + 2 B 9 9 c + 0 A 2 0 a + 1 A 1 1 B + + Sorting with a key function + + >>> df.sort_values(by='col4', key=lambda col: col.str.lower()) + col1 col2 col3 col4 + 0 A 2 0 a + 1 A 1 1 B + 2 B 9 9 c + 3 NaN 8 4 D + 4 D 7 2 e + 5 C 4 3 F + + Natural sort with the key argument, + using the `natsort ` package. + + >>> df = pd.DataFrame({ + ... "time": ['0hr', '128hr', '72hr', '48hr', '96hr'], + ... "value": [10, 20, 30, 40, 50] + ... }) + >>> df + time value + 0 0hr 10 + 1 128hr 20 + 2 72hr 30 + 3 48hr 40 + 4 96hr 50 + >>> from natsort import index_natsorted + >>> df.sort_values( + ... by="time", + ... key=lambda x: np.argsort(index_natsorted(df["time"])) + ... ) + time value + 0 0hr 10 + 3 48hr 40 + 2 72hr 30 + 4 96hr 50 + 1 128hr 20 + """ inplace = validate_bool_kwarg(inplace, "inplace") axis = self._get_axis_number(axis) ascending = validate_ascending(ascending) @@ -11451,52 +11459,6 @@ def quantile( result = self._constructor(res) return result.__finalize__(self, method="quantile") - @doc(NDFrame.asfreq, **_shared_doc_kwargs) - def asfreq( - self, - freq: Frequency, - method: FillnaOptions | None = None, - how: str | None = None, - normalize: bool = False, - fill_value: Hashable = None, - ) -> DataFrame: - return super().asfreq( - freq=freq, - method=method, - how=how, - normalize=normalize, - fill_value=fill_value, - ) - - @doc(NDFrame.resample, **_shared_doc_kwargs) - def resample( - self, - rule, - axis: Axis | lib.NoDefault = lib.no_default, - closed: str | None = None, - label: str | None = None, - convention: str = "start", - kind: str | None = None, - on: Level = None, - level: Level = None, - origin: str | TimestampConvertibleTypes = "start_day", - offset: TimedeltaConvertibleTypes | None = None, - group_keys: bool = False, - ) -> Resampler: - return super().resample( - rule=rule, - axis=axis, - closed=closed, - label=label, - convention=convention, - kind=kind, - on=on, - level=level, - origin=origin, - offset=offset, - group_keys=group_keys, - ) - def to_timestamp( self, freq: Frequency | None = None, diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 38bac75bd48b9..3b03532a7bee5 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -208,7 +208,7 @@ _shared_doc_kwargs = { "axes": "keywords for axes", "klass": "Series/DataFrame", - "axes_single_arg": "int or labels for object", + "axes_single_arg": "{0 or 'index'} for Series, {0 or 'index', 1 or 'columns'} for DataFrame", # noqa:E501 "args_transpose": "axes to permute (int or label for object)", "inplace": """ inplace : bool, default False @@ -5161,6 +5161,7 @@ def sort_index( def reindex( self, labels=None, + *, index=None, columns=None, axis: Axis | None = None, @@ -6834,7 +6835,11 @@ def fillna( ) -> Self | None: ... - @doc(**_shared_doc_kwargs) + @final + @doc( + klass=_shared_doc_kwargs["klass"], + axes_single_arg=_shared_doc_kwargs["axes_single_arg"], + ) def fillna( self, value: Hashable | Mapping | Series | DataFrame = None, @@ -7301,6 +7306,7 @@ def replace( ) -> Self | None: ... + @final @doc( _shared_docs["replace"], klass=_shared_doc_kwargs["klass"], @@ -8328,7 +8334,8 @@ def clip( return result - @doc(**_shared_doc_kwargs) + @final + @doc(klass=_shared_doc_kwargs["klass"]) def asfreq( self, freq: Frequency, @@ -8595,7 +8602,8 @@ def between_time( ) return self._take_with_is_copy(indexer, axis=axis) - @doc(**_shared_doc_kwargs) + @final + @doc(klass=_shared_doc_kwargs["klass"]) def resample( self, rule, @@ -8996,8 +9004,8 @@ def resample( ) else: warnings.warn( - "The 'axis' keyword in DataFrame.resample is deprecated and " - "will be removed in a future version.", + f"The 'axis' keyword in {type(self).__name__}.resample is " + "deprecated and will be removed in a future version.", FutureWarning, stacklevel=find_stack_level(), ) @@ -9392,7 +9400,11 @@ def compare( return diff - @doc(**_shared_doc_kwargs) + @final + @doc( + klass=_shared_doc_kwargs["klass"], + axes_single_arg=_shared_doc_kwargs["axes_single_arg"], + ) def align( self, other: NDFrameT, diff --git a/pandas/core/series.py b/pandas/core/series.py index 9c91badc57ce3..c288eaa251a46 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -148,7 +148,6 @@ from pandas._libs.internals import BlockValuesRefs from pandas._typing import ( AggFuncType, - AlignJoin, AnyAll, AnyArrayLike, ArrayLike, @@ -160,14 +159,11 @@ DtypeBackend, DtypeObj, FilePath, - FillnaOptions, - Frequency, IgnoreRaise, IndexKeyFunc, IndexLabel, Level, NaPosition, - NDFrameT, NumpySorter, NumpyValueArrayLike, QuantileInterpolation, @@ -178,8 +174,6 @@ SortKind, StorageOptions, Suffixes, - TimedeltaConvertibleTypes, - TimestampConvertibleTypes, ValueKeyFunc, WriteBuffer, npt, @@ -187,7 +181,6 @@ from pandas.core.frame import DataFrame from pandas.core.groupby.generic import SeriesGroupBy - from pandas.core.resample import Resampler __all__ = ["Series"] @@ -4558,38 +4551,6 @@ def _needs_reindex_multi(self, axes, method, level) -> bool: """ return False - # error: Cannot determine type of 'align' - @doc( - NDFrame.align, # type: ignore[has-type] - klass=_shared_doc_kwargs["klass"], - axes_single_arg=_shared_doc_kwargs["axes_single_arg"], - ) - def align( - self, - other: NDFrameT, - join: AlignJoin = "outer", - axis: Axis | None = None, - level: Level = None, - copy: bool | None = None, - fill_value: Hashable = None, - method: FillnaOptions | None | lib.NoDefault = lib.no_default, - limit: int | None | lib.NoDefault = lib.no_default, - fill_axis: Axis | lib.NoDefault = lib.no_default, - broadcast_axis: Axis | None | lib.NoDefault = lib.no_default, - ) -> tuple[Self, NDFrameT]: - return super().align( - other, - join=join, - axis=axis, - level=level, - copy=copy, - fill_value=fill_value, - method=method, - limit=limit, - fill_axis=fill_axis, - broadcast_axis=broadcast_axis, - ) - @overload def rename( self, @@ -4742,7 +4703,8 @@ def rename( """ ) @Substitution( - **_shared_doc_kwargs, + klass=_shared_doc_kwargs["klass"], + axes_single_arg=_shared_doc_kwargs["axes_single_arg"], extended_summary_sub="", axis_description_sub="", see_also_sub="", @@ -4952,65 +4914,6 @@ def drop( errors=errors, ) - @overload - def fillna( - self, - value: Hashable | Mapping | Series | DataFrame = ..., - *, - method: FillnaOptions | None = ..., - axis: Axis | None = ..., - inplace: Literal[False] = ..., - limit: int | None = ..., - downcast: dict | None = ..., - ) -> Series: - ... - - @overload - def fillna( - self, - value: Hashable | Mapping | Series | DataFrame = ..., - *, - method: FillnaOptions | None = ..., - axis: Axis | None = ..., - inplace: Literal[True], - limit: int | None = ..., - downcast: dict | None = ..., - ) -> None: - ... - - @overload - def fillna( - self, - value: Hashable | Mapping | Series | DataFrame = ..., - *, - method: FillnaOptions | None = ..., - axis: Axis | None = ..., - inplace: bool = ..., - limit: int | None = ..., - downcast: dict | None = ..., - ) -> Series | None: - ... - - @doc(NDFrame.fillna, **_shared_doc_kwargs) - def fillna( - self, - value: Hashable | Mapping | Series | DataFrame = None, - *, - method: FillnaOptions | None = None, - axis: Axis | None = None, - inplace: bool = False, - limit: int | None = None, - downcast: dict | None = None, - ) -> Series | None: - return super().fillna( - value=value, - method=method, - axis=axis, - inplace=inplace, - limit=limit, - downcast=downcast, - ) - def pop(self, item: Hashable) -> Any: """ Return item and drops from series. Raise KeyError if not found. @@ -5038,57 +4941,6 @@ def pop(self, item: Hashable) -> Any: """ return super().pop(item=item) - @overload - def replace( - self, - to_replace=..., - value=..., - *, - inplace: Literal[False] = ..., - limit: int | None = ..., - regex: bool = ..., - method: Literal["pad", "ffill", "bfill"] | lib.NoDefault = ..., - ) -> Series: - ... - - @overload - def replace( - self, - to_replace=..., - value=..., - *, - inplace: Literal[True], - limit: int | None = ..., - regex: bool = ..., - method: Literal["pad", "ffill", "bfill"] | lib.NoDefault = ..., - ) -> None: - ... - - @doc( - NDFrame.replace, - klass=_shared_doc_kwargs["klass"], - inplace=_shared_doc_kwargs["inplace"], - replace_iloc=_shared_doc_kwargs["replace_iloc"], - ) - def replace( - self, - to_replace=None, - value=lib.no_default, - *, - inplace: bool = False, - limit: int | None = None, - regex: bool = False, - method: Literal["pad", "ffill", "bfill"] | lib.NoDefault = lib.no_default, - ) -> Series | None: - return super().replace( - to_replace=to_replace, - value=value, - inplace=inplace, - limit=limit, - regex=regex, - method=method, - ) - @doc(INFO_DOCSTRING, **series_sub_kwargs) def info( self, @@ -5127,15 +4979,6 @@ def _replace_single(self, to_replace, method: str, inplace: bool, limit): return return result - # error: Cannot determine type of 'shift' - @doc(NDFrame.shift, klass=_shared_doc_kwargs["klass"]) # type: ignore[has-type] - def shift( - self, periods: int = 1, freq=None, axis: Axis = 0, fill_value: Hashable = None - ) -> Series: - return super().shift( - periods=periods, freq=freq, axis=axis, fill_value=fill_value - ) - def memory_usage(self, index: bool = True, deep: bool = False) -> int: """ Return the memory usage of the Series. @@ -5542,62 +5385,6 @@ def dropna( # ---------------------------------------------------------------------- # Time series-oriented methods - # error: Cannot determine type of 'asfreq' - @doc(NDFrame.asfreq, **_shared_doc_kwargs) # type: ignore[has-type] - def asfreq( - self, - freq: Frequency, - method: FillnaOptions | None = None, - how: str | None = None, - normalize: bool = False, - fill_value: Hashable = None, - ) -> Series: - return super().asfreq( - freq=freq, - method=method, - how=how, - normalize=normalize, - fill_value=fill_value, - ) - - # error: Cannot determine type of 'resample' - @doc(NDFrame.resample, **_shared_doc_kwargs) # type: ignore[has-type] - def resample( - self, - rule, - axis: Axis | lib.NoDefault = lib.no_default, - closed: str | None = None, - label: str | None = None, - convention: str = "start", - kind: str | None = None, - on: Level = None, - level: Level = None, - origin: str | TimestampConvertibleTypes = "start_day", - offset: TimedeltaConvertibleTypes | None = None, - group_keys: bool = False, - ) -> Resampler: - if axis is not lib.no_default: - warnings.warn( - "Series resample axis keyword is deprecated and will be removed in a " - "future version.", - FutureWarning, - stacklevel=find_stack_level(), - ) - - return super().resample( - rule=rule, - axis=axis, - closed=closed, - label=label, - convention=convention, - kind=kind, - on=on, - level=level, - origin=origin, - offset=offset, - group_keys=group_keys, - ) - def to_timestamp( self, freq=None, diff --git a/pandas/core/shared_docs.py b/pandas/core/shared_docs.py index 6d35bfef0d780..30ec5baf227eb 100644 --- a/pandas/core/shared_docs.py +++ b/pandas/core/shared_docs.py @@ -604,8 +604,10 @@ See Also -------- - {klass}.fillna : Fill NA values. - {klass}.where : Replace values based on boolean condition. + Series.fillna : Fill NA values. + DataFrame.fillna : Fill NA values. + Series.where : Replace values based on boolean condition. + DataFrame.where : Replace values based on boolean condition. DataFrame.applymap: Apply a function to a Dataframe elementwise. Series.map: Map values of Series according to an input mapping or function. Series.str.replace : Simple string replacement. diff --git a/pandas/tests/resample/test_resample_api.py b/pandas/tests/resample/test_resample_api.py index 1a0a5dfe213bd..c97fa93cbd660 100644 --- a/pandas/tests/resample/test_resample_api.py +++ b/pandas/tests/resample/test_resample_api.py @@ -1000,8 +1000,8 @@ def test_df_axis_param_depr(): def test_series_axis_param_depr(): warning_msg = ( - "Series resample axis keyword is deprecated and will be removed in a " - "future version." + "The 'axis' keyword in Series.resample is " + "deprecated and will be removed in a future version." ) with tm.assert_produces_warning(FutureWarning, match=warning_msg): test_series.resample("H", axis=0)