Skip to content

Commit 6b4ee6e

Browse files
fujiaxiangjreback
authored andcommitted
BUG: Series __setitem__ gives wrong result with bool indexer (#30580)
1 parent 44d6b28 commit 6b4ee6e

File tree

3 files changed

+24
-8
lines changed

3 files changed

+24
-8
lines changed

doc/source/whatsnew/v1.0.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -864,6 +864,7 @@ Indexing
864864
- Bug when indexing with ``.loc`` where the index was a :class:`CategoricalIndex` with non-string categories didn't work (:issue:`17569`, :issue:`30225`)
865865
- :meth:`Index.get_indexer_non_unique` could fail with `TypeError` in some cases, such as when searching for ints in a string index (:issue:`28257`)
866866
- Bug in :meth:`Float64Index.get_loc` incorrectly raising ``TypeError`` instead of ``KeyError`` (:issue:`29189`)
867+
- Bug in :meth:`Series.__setitem__` incorrectly assigning values with boolean indexer when the length of new data matches the number of ``True`` values and new data is not a ``Series`` or an ``np.array`` (:issue:`30567`)
867868

868869
Missing
869870
^^^^^^^

pandas/core/internals/blocks.py

+13-8
Original file line numberDiff line numberDiff line change
@@ -943,15 +943,20 @@ def putmask(self, mask, new, align=True, inplace=False, axis=0, transpose=False)
943943
and np.any(mask[mask])
944944
and getattr(new, "ndim", 1) == 1
945945
):
946-
947-
if not (
948-
mask.shape[-1] == len(new)
949-
or mask[mask].shape[-1] == len(new)
950-
or len(new) == 1
951-
):
946+
if mask[mask].shape[-1] == len(new):
947+
# GH 30567
948+
# If length of ``new`` is less than the length of ``new_values``,
949+
# `np.putmask` would first repeat the ``new`` array and then
950+
# assign the masked values hence produces incorrect result.
951+
# `np.place` on the other hand uses the ``new`` values at it is
952+
# to place in the masked locations of ``new_values``
953+
np.place(new_values, mask, new)
954+
elif mask.shape[-1] == len(new) or len(new) == 1:
955+
np.putmask(new_values, mask, new)
956+
else:
952957
raise ValueError("cannot assign mismatch length to masked array")
953-
954-
np.putmask(new_values, mask, new)
958+
else:
959+
np.putmask(new_values, mask, new)
955960

956961
# maybe upcast me
957962
elif mask.any():

pandas/tests/indexing/test_indexing.py

+10
Original file line numberDiff line numberDiff line change
@@ -1190,3 +1190,13 @@ def test_duplicate_index_mistyped_key_raises_keyerror():
11901190

11911191
with pytest.raises(KeyError):
11921192
ser.index._engine.get_loc(None)
1193+
1194+
1195+
def test_setitem_with_bool_mask_and_values_matching_n_trues_in_length():
1196+
# GH 30567
1197+
ser = pd.Series([None] * 10)
1198+
mask = [False] * 3 + [True] * 5 + [False] * 2
1199+
ser[mask] = range(5)
1200+
result = ser
1201+
expected = pd.Series([None] * 3 + list(range(5)) + [None] * 2).astype("object")
1202+
tm.assert_series_equal(result, expected)

0 commit comments

Comments
 (0)