Skip to content

BUG: fix length_of_indexer with boolean mask #31897

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 18, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion pandas/core/indexers.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ def maybe_convert_indices(indices, n: int):

def length_of_indexer(indexer, target=None) -> int:
"""
Return the length of a single non-tuple indexer which could be a slice.
Return the expected length of target[indexer]

Returns
-------
Expand All @@ -245,6 +245,12 @@ def length_of_indexer(indexer, target=None) -> int:
step = -step
return (stop - start + step - 1) // step
elif isinstance(indexer, (ABCSeries, ABCIndexClass, np.ndarray, list)):
if isinstance(indexer, list):
indexer = np.array(indexer)

if indexer.dtype == bool:
# GH#25774
return indexer.sum()
return len(indexer)
elif not is_list_like_indexer(indexer):
return 1
Expand Down
28 changes: 7 additions & 21 deletions pandas/core/indexing.py
Original file line number Diff line number Diff line change
Expand Up @@ -1702,31 +1702,17 @@ def _setitem_with_indexer(self, indexer, value):

plane_indexer = tuple([idx]) + indexer[info_axis + 1 :]
lplane_indexer = length_of_indexer(plane_indexer[0], index)
# lplane_indexer gives the expected length of obj[idx]

# require that we are setting the right number of values that
# we are indexing
if (
is_list_like_indexer(value)
and np.iterable(value)
and lplane_indexer != len(value)
):

if len(obj[idx]) != len(value):
raise ValueError(
"cannot set using a multi-index "
"selection indexer with a different "
"length than the value"
)

# make sure we have an ndarray
value = getattr(value, "values", value).ravel()
if is_list_like_indexer(value) and lplane_indexer != len(value):

# we can directly set the series here
obj._consolidate_inplace()
obj = obj.copy()
obj._data = obj._data.setitem(indexer=tuple([idx]), value=value)
self.obj[item] = obj
return
raise ValueError(
"cannot set using a multi-index "
"selection indexer with a different "
"length than the value"
)

# non-mi
else:
Expand Down
11 changes: 11 additions & 0 deletions pandas/tests/test_indexers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Tests aimed at pandas.core.indexers
import numpy as np

from pandas.core.indexers import length_of_indexer


def test_length_of_indexer():
arr = np.zeros(4, dtype=bool)
arr[0] = 1
result = length_of_indexer(arr)
assert result == 1