diff --git a/doc/source/whatsnew/v2.0.0.rst b/doc/source/whatsnew/v2.0.0.rst index e2705b353858b..8896799ffa613 100644 --- a/doc/source/whatsnew/v2.0.0.rst +++ b/doc/source/whatsnew/v2.0.0.rst @@ -1276,6 +1276,7 @@ Indexing - Bug in :meth:`DataFrame.sort_values` where ``None`` was not returned when ``by`` is empty list and ``inplace=True`` (:issue:`50643`) - Bug in :meth:`DataFrame.loc` coercing dtypes when setting values with a list indexer (:issue:`49159`) - Bug in :meth:`Series.loc` raising error for out of bounds end of slice indexer (:issue:`50161`) +- Bug in :meth:`DataFrame.loc` raising ``ValueError`` with all ``False`` ``bool`` indexer and empty object (:issue:`51450`) - Bug in :meth:`DataFrame.loc` raising ``ValueError`` with ``bool`` indexer and :class:`MultiIndex` (:issue:`47687`) - Bug in :meth:`DataFrame.loc` raising ``IndexError`` when setting values for a pyarrow-backed column with a non-scalar indexer (:issue:`50085`) - Bug in :meth:`DataFrame.__getitem__`, :meth:`Series.__getitem__`, :meth:`DataFrame.__setitem__` and :meth:`Series.__setitem__` diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py index c1435ebbe39ef..4c5bc659897d1 100644 --- a/pandas/core/indexing.py +++ b/pandas/core/indexing.py @@ -69,7 +69,6 @@ ) from pandas.core.indexers import ( check_array_indexer, - is_empty_indexer, is_list_like_indexer, is_scalar_indexer, length_of_indexer, @@ -755,14 +754,8 @@ def _maybe_mask_setitem_value(self, indexer, value): if ndim == 1: # We implicitly broadcast, though numpy does not, see # github.com/pandas-dev/pandas/pull/45501#discussion_r789071825 - if len(newkey) == 0: - # FIXME: kludge for - # test_setitem_loc_only_false_indexer_dtype_changed - # TODO(GH#45333): may be fixed when deprecation is enforced - value = value.iloc[:0] - else: - # test_loc_setitem_ndframe_values_alignment - value = self.obj.iloc._align_series(indexer, value) + # test_loc_setitem_ndframe_values_alignment + value = self.obj.iloc._align_series(indexer, value) indexer = (newkey, icols) elif ndim == 2 and value.shape[1] == 1: @@ -2239,9 +2232,6 @@ def ravel(i): # we have a frame, with multiple indexers on both axes; and a # series, so need to broadcast (see GH5206) if sum_aligners == self.ndim and all(is_sequence(_) for _ in indexer): - # TODO: This is hacky, align Series and DataFrame behavior GH#45778 - if obj.ndim == 2 and is_empty_indexer(indexer[0]): - return ser._values.copy() ser_values = ser.reindex(obj.axes[0][indexer[0]], copy=True)._values # single indexer diff --git a/pandas/tests/indexing/test_loc.py b/pandas/tests/indexing/test_loc.py index 44c0b654db268..bbea179843f3a 100644 --- a/pandas/tests/indexing/test_loc.py +++ b/pandas/tests/indexing/test_loc.py @@ -2599,6 +2599,20 @@ def test_loc_setitem_ndframe_values_alignment(self, using_copy_on_write): else: tm.assert_frame_equal(df, expected) + def test_loc_indexer_empty_broadcast(self): + # GH#51450 + df = DataFrame({"a": [], "b": []}, dtype=object) + expected = df.copy() + df.loc[np.array([], dtype=np.bool_), ["a"]] = df["a"] + tm.assert_frame_equal(df, expected) + + def test_loc_indexer_all_false_broadcast(self): + # GH#51450 + df = DataFrame({"a": ["x"], "b": ["y"]}, dtype=object) + expected = df.copy() + df.loc[np.array([False], dtype=np.bool_), ["a"]] = df["b"] + tm.assert_frame_equal(df, expected) + class TestLocListlike: @pytest.mark.parametrize("box", [lambda x: x, np.asarray, list])