From 268f5e53782b8afb7d1acfc5e5e6afcc312a503b Mon Sep 17 00:00:00 2001 From: Lawrence Mitchell Date: Wed, 21 Jun 2023 12:11:42 +0100 Subject: [PATCH] Update documentation and add test --- doc/source/user_guide/indexing.rst | 18 ++++++++++++++++++ doc/source/whatsnew/v2.1.0.rst | 1 + pandas/core/indexing.py | 3 ++- pandas/tests/frame/indexing/test_indexing.py | 8 ++++++++ 4 files changed, 29 insertions(+), 1 deletion(-) diff --git a/doc/source/user_guide/indexing.rst b/doc/source/user_guide/indexing.rst index 77eee8e58a5e8..e514d3c320265 100644 --- a/doc/source/user_guide/indexing.rst +++ b/doc/source/user_guide/indexing.rst @@ -62,6 +62,8 @@ of multi-axis indexing. * A boolean array (any ``NA`` values will be treated as ``False``). * A ``callable`` function with one argument (the calling Series or DataFrame) and that returns valid output for indexing (one of the above). + * A tuple of row (and column) indices whose elements are one of the + above inputs. See more at :ref:`Selection by Label `. @@ -78,6 +80,8 @@ of multi-axis indexing. * A boolean array (any ``NA`` values will be treated as ``False``). * A ``callable`` function with one argument (the calling Series or DataFrame) and that returns valid output for indexing (one of the above). + * A tuple of row (and column) indices whose elements are one of the + above inputs. See more at :ref:`Selection by Position `, :ref:`Advanced Indexing ` and :ref:`Advanced @@ -85,6 +89,12 @@ of multi-axis indexing. * ``.loc``, ``.iloc``, and also ``[]`` indexing can accept a ``callable`` as indexer. See more at :ref:`Selection By Callable `. + .. note:: + + Destructuring tuple keys into row (and column) indexes occurs + *before* callables are applied, so you cannot return a tuple from + a callable to index both rows and columns. + Getting values from an object with multi-axes selection uses the following notation (using ``.loc`` as an example, but the following applies to ``.iloc`` as well). Any of the axes accessors may be the null slice ``:``. Axes left out of @@ -446,6 +456,8 @@ The ``.iloc`` attribute is the primary access method. The following are valid in * A slice object with ints ``1:7``. * A boolean array. * A ``callable``, see :ref:`Selection By Callable `. +* A tuple of row (and column) indexes, whose elements are one of the + above types. .. ipython:: python @@ -547,6 +559,12 @@ Selection by callable ``.loc``, ``.iloc``, and also ``[]`` indexing can accept a ``callable`` as indexer. The ``callable`` must be a function with one argument (the calling Series or DataFrame) that returns valid output for indexing. +.. note:: + + For ``.iloc`` indexing, returning a tuple from the callable is + not supported, since tuple destructuring for row and column indexes + occurs *before* applying callables. + .. ipython:: python df1 = pd.DataFrame(np.random.randn(6, 4), diff --git a/doc/source/whatsnew/v2.1.0.rst b/doc/source/whatsnew/v2.1.0.rst index 44691e4265f5b..69f214ea96d03 100644 --- a/doc/source/whatsnew/v2.1.0.rst +++ b/doc/source/whatsnew/v2.1.0.rst @@ -298,6 +298,7 @@ Deprecations - Deprecated parameter ``obj`` in :meth:`GroupBy.get_group` (:issue:`53545`) - Deprecated positional indexing on :class:`Series` with :meth:`Series.__getitem__` and :meth:`Series.__setitem__`, in a future version ``ser[item]`` will *always* interpret ``item`` as a label, not a position (:issue:`50617`) - Deprecated strings ``T``, ``t``, ``L`` and ``l`` denoting units in :func:`to_timedelta` (:issue:`52536`) +- Deprecated support for returning a tuple from a callable in ``iloc``-indexing. Place callables inside a tuple if you need to generate row and column indices using functions (:issue:`53533`) - Deprecated the "method" and "limit" keywords on :meth:`Series.fillna`, :meth:`DataFrame.fillna`, :meth:`SeriesGroupBy.fillna`, :meth:`DataFrameGroupBy.fillna`, and :meth:`Resampler.fillna`, use ``obj.bfill()`` or ``obj.ffill()`` instead (:issue:`53394`) - Deprecated the ``method`` and ``limit`` keywords in :meth:`DataFrame.replace` and :meth:`Series.replace` (:issue:`33302`) - Deprecated values "pad", "ffill", "bfill", "backfill" for :meth:`Series.interpolate` and :meth:`DataFrame.interpolate`, use ``obj.ffill()`` or ``obj.bfill()`` instead (:issue:`53581`) diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py index 381f9c6ab0897..5666c932c712b 100644 --- a/pandas/core/indexing.py +++ b/pandas/core/indexing.py @@ -163,7 +163,8 @@ def iloc(self) -> _iLocIndexer: - A ``callable`` function with one argument (the calling Series or DataFrame) and that returns valid output for indexing (one of the above). This is useful in method chains, when you don't have a reference to the - calling object, but would like to base your selection on some value. + calling object, but would like to base your selection on + some value. Note that returning a tuple from a callable is deprecated. - A tuple of row and column indexes. The tuple elements consist of one of the above inputs, e.g. ``(0, 1)``. diff --git a/pandas/tests/frame/indexing/test_indexing.py b/pandas/tests/frame/indexing/test_indexing.py index 9005798d66d17..159c7ec18a2b0 100644 --- a/pandas/tests/frame/indexing/test_indexing.py +++ b/pandas/tests/frame/indexing/test_indexing.py @@ -1000,6 +1000,14 @@ def test_single_element_ix_dont_upcast(self, float_frame): result = df.loc[[0], "b"] tm.assert_series_equal(result, expected) + def test_iloc_callable_tuple_return_value(self): + df = DataFrame(np.random.randn(10, 4), index=range(0, 20, 2)) + msg = "callable in iLocation indexing is deprecated" + with tm.assert_produces_warning(FutureWarning, match=msg): + df.iloc[lambda _: (0,)] + with tm.assert_produces_warning(FutureWarning, match=msg): + df.iloc[lambda _: (0,)] = 1 + def test_iloc_row(self): df = DataFrame(np.random.randn(10, 4), index=range(0, 20, 2))