Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
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
1 change: 1 addition & 0 deletions doc/source/whatsnew/v1.2.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,7 @@ Indexing
- Bug in :meth:`DataFrame.iloc` and :meth:`Series.iloc` aligning objects in ``__setitem__`` (:issue:`22046`)
- Bug in :meth:`DataFrame.loc` did not raise ``KeyError`` when missing combination was given with ``slice(None)`` for remaining levels (:issue:`19556`)
- Bug in :meth:`DataFrame.loc` raising ``TypeError`` when non-integer slice was given to select values from :class:`MultiIndex` (:issue:`25165`, :issue:`24263`)
- Bug in :meth:`DataFrame.loc` returning and assigning elements in wrong order when indexer is differently ordered than the :class:`MultiIndex` to filter (:issue:`31330`, :issue:`34603`)

Missing
^^^^^^^
Expand Down
8 changes: 7 additions & 1 deletion pandas/core/indexes/multi.py
Original file line number Diff line number Diff line change
Expand Up @@ -3262,7 +3262,7 @@ def _update_indexer(
self._get_level_indexer(x, level=i, indexer=indexer)
)
indexers = (idxrs if indexers is None else indexers).union(
idxrs
idxrs, sort=False
)
except KeyError:

Expand Down Expand Up @@ -3349,6 +3349,9 @@ def _reorder_indexer(
# order they appears in a list-like sequence
# This mapping is then use to reorder the indexer
for i, k in enumerate(seq):
if is_scalar(k):
# GH#34603 we want to treat a scalar the same as an all equal list
k = [k]
if com.is_bool_indexer(k):
new_order = np.arange(n)[indexer]
elif is_list_like(k):
Expand All @@ -3362,6 +3365,9 @@ def _reorder_indexer(
key_order_map[level_indexer] = np.arange(len(level_indexer))

new_order = key_order_map[self.codes[i][indexer]]
elif isinstance(k, slice) and k.start is None and k.stop is None:
# slice(None) should not determine order GH#31330
new_order = np.ones((n,))[indexer]
else:
# For all other case, use the same order as the level
new_order = np.arange(n)[indexer]
Expand Down
27 changes: 27 additions & 0 deletions pandas/tests/indexing/multiindex/test_loc.py
Original file line number Diff line number Diff line change
Expand Up @@ -668,3 +668,30 @@ def test_get_loc_datetime_index():
# Check if get_loc matches for Index and MultiIndex
assert mi.get_loc("2001-01") == slice(0, 31, None)
assert index.get_loc("2001-01") == slice(0, 31, None)


def test_loc_setitem_indexer_differently_ordered():
# GH#34603
mi = MultiIndex.from_product([["a", "b"], [0, 1]])
df = DataFrame([[1, 2], [3, 4], [5, 6], [7, 8]], index=mi)

indexer = ("a", [1, 0])
df.loc[indexer, :] = np.array([[9, 10], [11, 12]])
expected = DataFrame([[11, 12], [9, 10], [5, 6], [7, 8]], index=mi)
tm.assert_frame_equal(df, expected)


def test_loc_getitem_index_differently_ordered_slice_none():
# GH#31330
df = DataFrame(
[[1, 2], [3, 4], [5, 6], [7, 8]],
index=[["a", "a", "b", "b"], [1, 2, 1, 2]],
columns=["a", "b"],
)
result = df.loc[(slice(None), [2, 1]), :]
expected = DataFrame(
[[3, 4], [7, 8], [1, 2], [5, 6]],
index=[["a", "b", "a", "b"], [2, 2, 1, 1]],
columns=["a", "b"],
)
tm.assert_frame_equal(result, expected)