diff --git a/doc/source/whatsnew/v2.2.0.rst b/doc/source/whatsnew/v2.2.0.rst index 5de5bd58bd35f..f92a9b71a2781 100644 --- a/doc/source/whatsnew/v2.2.0.rst +++ b/doc/source/whatsnew/v2.2.0.rst @@ -657,6 +657,24 @@ Set the following option to opt into the future behavior: In [9]: pd.set_option("future.no_silent_downcasting", True) +Deprecated list-like-column-wise enlargement with partial row indexer +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Enlarging a dataframe with a partial row indexer and a list-like column indexer is deprecated. + +Instead of (suppose ``'A'`` and ``'B'`` are not already columns in ``df``) + +.. code-block:: python + + df.loc[idx, ['A', 'B']] = (val_1, val_2) + +please do + +.. code-block:: python + + df.loc[idx, 'A'] = val_1 + df.loc[idx, 'B'] = val_2 + Other Deprecations ^^^^^^^^^^^^^^^^^^ - Changed :meth:`Timedelta.resolution_string` to return ``h``, ``min``, ``s``, ``ms``, ``us``, and ``ns`` instead of ``H``, ``T``, ``S``, ``L``, ``U``, and ``N``, for compatibility with respective deprecations in frequency aliases (:issue:`52536`) diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py index 0f892d4924933..8a66f94ebbe10 100644 --- a/pandas/core/indexing.py +++ b/pandas/core/indexing.py @@ -877,7 +877,20 @@ def _ensure_listlike_indexer(self, key, axis=None, value=None) -> None: ) self.obj._mgr = new_mgr return - + if len(diff): + warnings.warn( + ( + "list-like-column-wise enlargement with partial-row-wise " + "indexer is deprecated.\n" + "Instead of\n" + " df.loc[idx, ['A', 'B']] = (val_1, val_2)\n" + "please do\n" + " df.loc[idx, 'A'] = val_1\n" + " df.loc[idx, 'B'] = val_2\n" + ), + FutureWarning, + stacklevel=find_stack_level(), + ) self.obj._mgr = self.obj._mgr.reindex_axis(keys, axis=0, only_slice=True) @final diff --git a/pandas/tests/indexing/multiindex/test_loc.py b/pandas/tests/indexing/multiindex/test_loc.py index de7d644698f2c..8e4d7991d6f7d 100644 --- a/pandas/tests/indexing/multiindex/test_loc.py +++ b/pandas/tests/indexing/multiindex/test_loc.py @@ -377,7 +377,15 @@ def test_multiindex_setitem_columns_enlarging(self, indexer, exp_value): # GH#39147 mi = MultiIndex.from_tuples([(1, 2), (3, 4)]) df = DataFrame([[1, 2], [3, 4]], index=mi, columns=["a", "b"]) - df.loc[indexer, ["c", "d"]] = 1.0 + warn = FutureWarning if indexer != slice(None) else None + with tm.assert_produces_warning( + warn, + match=( + "list-like-column-wise enlargement with partial-row-wise indexer " + "is deprecated" + ), + ): + df.loc[indexer, ["c", "d"]] = 1.0 expected = DataFrame( [[1, 2, 1.0, 1.0], [3, 4, exp_value, exp_value]], index=mi, diff --git a/pandas/tests/indexing/test_loc.py b/pandas/tests/indexing/test_loc.py index c446f2c44b745..e40066a51db97 100644 --- a/pandas/tests/indexing/test_loc.py +++ b/pandas/tests/indexing/test_loc.py @@ -940,8 +940,12 @@ def test_loc_setitem_with_scalar_index(self, indexer, value): def test_loc_setitem_missing_columns(self, index, box, expected): # GH 29334 df = DataFrame([[1, 2], [3, 4], [5, 6]], columns=["A", "B"]) - - df.loc[index] = box + warn = FutureWarning if index[0] != slice(None, None, None) else None + with tm.assert_produces_warning( + warn, + match=("list-like-column-wise enlargement with partial-row-wise indexer"), + ): + df.loc[index] = box tm.assert_frame_equal(df, expected) def test_loc_coercion(self): @@ -3327,7 +3331,14 @@ def test_loc_setitem_dict_timedelta_multiple_set(self): def test_loc_set_multiple_items_in_multiple_new_columns(self): # GH 25594 df = DataFrame(index=[1, 2], columns=["a"]) - df.loc[1, ["b", "c"]] = [6, 7] + with tm.assert_produces_warning( + FutureWarning, + match=( + "list-like-column-wise enlargement with partial-row-wise indexer " + "is deprecated" + ), + ): + df.loc[1, ["b", "c"]] = [6, 7] expected = DataFrame( {